]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
CIFS: Allow null nd (as nfs server uses) on create
authorSteve French <sfrench@us.ibm.com>
Thu, 22 Apr 2010 19:21:55 +0000 (19:21 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 5 Jul 2010 18:11:14 +0000 (11:11 -0700)
commit fa588e0c57048b3d4bfcd772d80dc0615f83fd35 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: Shirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
fs/cifs/cifsproto.h
fs/cifs/dir.c
fs/cifs/file.c

index 5646727e33f543f70ec449b390d8955b66852dc9..05a9b776e1a8132a3853a09f20ae13d8f79abd8e 100644 (file)
@@ -95,8 +95,10 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode,
                                __u16 fileHandle, struct file *file,
                                struct vfsmount *mnt, unsigned int oflags);
 extern int cifs_posix_open(char *full_path, struct inode **pinode,
-                          struct vfsmount *mnt, int mode, int oflags,
-                          __u32 *poplock, __u16 *pnetfid, int xid);
+                               struct vfsmount *mnt,
+                               struct super_block *sb,
+                               int mode, int oflags,
+                               __u32 *poplock, __u16 *pnetfid, int xid);
 extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
                                     FILE_UNIX_BASIC_INFO *info,
                                     struct cifs_sb_info *cifs_sb);
index 1f42f772865a54f1f45b516b090533a4a4715bf4..c3d6182d0ebe4a6cb926482a66694791eced5db4 100644 (file)
@@ -183,13 +183,14 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
 }
 
 int cifs_posix_open(char *full_path, struct inode **pinode,
-                   struct vfsmount *mnt, int mode, int oflags,
-                   __u32 *poplock, __u16 *pnetfid, int xid)
+                       struct vfsmount *mnt, struct super_block *sb,
+                       int mode, int oflags,
+                       __u32 *poplock, __u16 *pnetfid, int xid)
 {
        int rc;
        FILE_UNIX_BASIC_INFO *presp_data;
        __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;
 
        cFYI(1, ("posix open %s", full_path));
@@ -241,7 +242,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
 
        /* get new inode and set it up */
        if (*pinode == NULL) {
-               *pinode = cifs_iget(mnt->mnt_sb, &fattr);
+               *pinode = cifs_iget(sb, &fattr);
                if (!*pinode) {
                        rc = -ENOMEM;
                        goto posix_open_ret;
@@ -250,7 +251,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
                cifs_fattr_to_inode(*pinode, &fattr);
        }
 
-       cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);
+       if (mnt)
+               cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);
 
 posix_open_ret:
        kfree(presp_data);
@@ -314,13 +316,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        if (nd && (nd->flags & LOOKUP_OPEN))
                oflags = nd->intent.open.flags;
        else
-               oflags = FMODE_READ;
+               oflags = FMODE_READ | SMB_O_CREAT;
 
        if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-               rc = cifs_posix_open(full_path, &newinode, nd->path.mnt,
-                                    mode, oflags, &oplock, &fileHandle, xid);
+               rc = cifs_posix_open(full_path, &newinode,
+                       nd ? nd->path.mnt : NULL,
+                       inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
                /* EIO could indicate that (posix open) operation is not
                   supported, despite what server claimed in capability
                   negotation.  EREMOTE indicates DFS junction, which is not
@@ -677,6 +680,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
                     (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
                     (nd->intent.open.flags & O_CREAT)) {
                        rc = cifs_posix_open(full_path, &newInode, nd->path.mnt,
+                                       parent_dir_inode->i_sb,
                                        nd->intent.open.create_mode,
                                        nd->intent.open.flags, &oplock,
                                        &fileHandle, xid);
index 429337eb7afec9f0933c72927eedcc7412207c88..5d1099a20cceda7f33a85869bf810a0b4f51af55 100644 (file)
@@ -295,10 +295,12 @@ int cifs_open(struct inode *inode, struct file *file)
            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
                int oflags = (int) cifs_posix_convert_flags(file->f_flags);
+               oflags |= SMB_O_CREAT;
                /* can not refresh inode info since size could be stale */
                rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
-                                    cifs_sb->mnt_file_mode /* ignored */,
-                                    oflags, &oplock, &netfid, xid);
+                               inode->i_sb,
+                               cifs_sb->mnt_file_mode /* ignored */,
+                               oflags, &oplock, &netfid, xid);
                if (rc == 0) {
                        cFYI(1, ("posix open succeeded"));
                        /* no need for special case handling of setting mode
@@ -510,8 +512,9 @@ reopen_error_exit:
                int oflags = (int) cifs_posix_convert_flags(file->f_flags);
                /* can not refresh inode info since size could be stale */
                rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
-                                    cifs_sb->mnt_file_mode /* ignored */,
-                                    oflags, &oplock, &netfid, xid);
+                               inode->i_sb,
+                               cifs_sb->mnt_file_mode /* ignored */,
+                               oflags, &oplock, &netfid, xid);
                if (rc == 0) {
                        cFYI(1, ("posix reopen succeeded"));
                        goto reopen_success;