Commit 31ccb085 authored by Steve French's avatar Steve French Committed by Greg Kroah-Hartman

CIFS: Allow null nd (as nfs server uses) on create

commit fa588e0c upstream.

While creating a file on a server which supports unix extensions
such as Samba, if a file is being created which does not supply
nameidata (i.e. nd is null), cifs client can oops when calling
cifs_posix_open.
Signed-off-by: default avatarShirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 55442a2a
...@@ -95,7 +95,9 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, ...@@ -95,7 +95,9 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode,
__u16 fileHandle, struct file *file, __u16 fileHandle, struct file *file,
struct vfsmount *mnt, unsigned int oflags); struct vfsmount *mnt, unsigned int oflags);
extern int cifs_posix_open(char *full_path, struct inode **pinode, extern int cifs_posix_open(char *full_path, struct inode **pinode,
struct vfsmount *mnt, int mode, int oflags, struct vfsmount *mnt,
struct super_block *sb,
int mode, int oflags,
__u32 *poplock, __u16 *pnetfid, int xid); __u32 *poplock, __u16 *pnetfid, int xid);
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
FILE_UNIX_BASIC_INFO *info, FILE_UNIX_BASIC_INFO *info,
......
...@@ -183,13 +183,14 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, ...@@ -183,13 +183,14 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
} }
int cifs_posix_open(char *full_path, struct inode **pinode, int cifs_posix_open(char *full_path, struct inode **pinode,
struct vfsmount *mnt, int mode, int oflags, struct vfsmount *mnt, struct super_block *sb,
int mode, int oflags,
__u32 *poplock, __u16 *pnetfid, int xid) __u32 *poplock, __u16 *pnetfid, int xid)
{ {
int rc; int rc;
FILE_UNIX_BASIC_INFO *presp_data; FILE_UNIX_BASIC_INFO *presp_data;
__u32 posix_flags = 0; __u32 posix_flags = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_fattr fattr; struct cifs_fattr fattr;
cFYI(1, ("posix open %s", full_path)); cFYI(1, ("posix open %s", full_path));
...@@ -242,7 +243,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, ...@@ -242,7 +243,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
/* get new inode and set it up */ /* get new inode and set it up */
if (*pinode == NULL) { if (*pinode == NULL) {
*pinode = cifs_iget(mnt->mnt_sb, &fattr); *pinode = cifs_iget(sb, &fattr);
if (!*pinode) { if (!*pinode) {
rc = -ENOMEM; rc = -ENOMEM;
goto posix_open_ret; goto posix_open_ret;
...@@ -251,6 +252,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, ...@@ -251,6 +252,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
cifs_fattr_to_inode(*pinode, &fattr); cifs_fattr_to_inode(*pinode, &fattr);
} }
if (mnt)
cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags); cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);
posix_open_ret: posix_open_ret:
...@@ -315,13 +317,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -315,13 +317,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if (nd && (nd->flags & LOOKUP_OPEN)) if (nd && (nd->flags & LOOKUP_OPEN))
oflags = nd->intent.open.flags; oflags = nd->intent.open.flags;
else else
oflags = FMODE_READ; oflags = FMODE_READ | SMB_O_CREAT;
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP & (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) { le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = cifs_posix_open(full_path, &newinode, nd->path.mnt, rc = cifs_posix_open(full_path, &newinode,
mode, oflags, &oplock, &fileHandle, xid); nd ? nd->path.mnt : NULL,
inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
/* EIO could indicate that (posix open) operation is not /* EIO could indicate that (posix open) operation is not
supported, despite what server claimed in capability supported, despite what server claimed in capability
negotation. EREMOTE indicates DFS junction, which is not negotation. EREMOTE indicates DFS junction, which is not
...@@ -678,6 +681,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -678,6 +681,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
(nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
(nd->intent.open.flags & O_CREAT)) { (nd->intent.open.flags & O_CREAT)) {
rc = cifs_posix_open(full_path, &newInode, nd->path.mnt, rc = cifs_posix_open(full_path, &newInode, nd->path.mnt,
parent_dir_inode->i_sb,
nd->intent.open.create_mode, nd->intent.open.create_mode,
nd->intent.open.flags, &oplock, nd->intent.open.flags, &oplock,
&fileHandle, xid); &fileHandle, xid);
......
...@@ -298,8 +298,10 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -298,8 +298,10 @@ int cifs_open(struct inode *inode, struct file *file)
(CIFS_UNIX_POSIX_PATH_OPS_CAP & (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) { le64_to_cpu(tcon->fsUnixInfo.Capability))) {
int oflags = (int) cifs_posix_convert_flags(file->f_flags); int oflags = (int) cifs_posix_convert_flags(file->f_flags);
oflags |= SMB_O_CREAT;
/* can not refresh inode info since size could be stale */ /* can not refresh inode info since size could be stale */
rc = cifs_posix_open(full_path, &inode, file->f_path.mnt, rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
inode->i_sb,
cifs_sb->mnt_file_mode /* ignored */, cifs_sb->mnt_file_mode /* ignored */,
oflags, &oplock, &netfid, xid); oflags, &oplock, &netfid, xid);
if (rc == 0) { if (rc == 0) {
...@@ -513,6 +515,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) ...@@ -513,6 +515,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
int oflags = (int) cifs_posix_convert_flags(file->f_flags); int oflags = (int) cifs_posix_convert_flags(file->f_flags);
/* can not refresh inode info since size could be stale */ /* can not refresh inode info since size could be stale */
rc = cifs_posix_open(full_path, NULL, file->f_path.mnt, rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
inode->i_sb,
cifs_sb->mnt_file_mode /* ignored */, cifs_sb->mnt_file_mode /* ignored */,
oflags, &oplock, &netfid, xid); oflags, &oplock, &netfid, xid);
if (rc == 0) { if (rc == 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment