]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Feb 2014 18:33:50 +0000 (10:33 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Feb 2014 18:33:50 +0000 (10:33 -0800)
Pull CIFS fixes from Steve French:
 "Small fix from Jeff for writepages leak, and some fixes for ACLs and
  xattrs when SMB2 enabled.

  Am expecting another fix from Jeff and at least one more fix (for
  mounting SMB2 with cifsacl) in the next week"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  [CIFS] clean up page array when uncached write send fails
  cifs: use a flexarray in cifs_writedata
  retrieving CIFS ACLs when mounted with SMB2 fails dropping session
  Add protocol specific operation for CIFS xattrs

fs/cifs/cifsacl.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smb1ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h
fs/cifs/xattr.c

index 8f9b4f710d4a31ea651f64586fa2469edd92c2fa..c819b0bd491aab9bf587987b7b4017cdb5c69f64 100644 (file)
@@ -1043,15 +1043,30 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
        __u32 secdesclen = 0;
        struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
        struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
+       struct cifs_tcon *tcon;
+
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
 
        cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
 
        /* Get the security descriptor */
-       pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
+
+       if (tcon->ses->server->ops->get_acl == NULL) {
+               cifs_put_tlink(tlink);
+               return -EOPNOTSUPP;
+       }
+
+       pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
+                                               &secdesclen);
        if (IS_ERR(pntsd)) {
                rc = PTR_ERR(pntsd);
                cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
-               goto out;
+               cifs_put_tlink(tlink);
+               return rc;
        }
 
        /*
@@ -1064,6 +1079,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
        pnntsd = kmalloc(secdesclen, GFP_KERNEL);
        if (!pnntsd) {
                kfree(pntsd);
+               cifs_put_tlink(tlink);
                return -ENOMEM;
        }
 
@@ -1072,14 +1088,18 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
 
        cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
 
+       if (tcon->ses->server->ops->set_acl == NULL)
+               rc = -EOPNOTSUPP;
+
        if (!rc) {
                /* Set the security descriptor */
-               rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
+               rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
+                                                    path, aclflag);
                cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
        }
+       cifs_put_tlink(tlink);
 
        kfree(pnntsd);
        kfree(pntsd);
-out:
        return rc;
 }
index a245d1809ed8d63dc7ee5cbc5320bb117a12c71e..86dc28c7aa5c7b9a0f4652e3d5a09957d8c6883e 100644 (file)
@@ -323,7 +323,8 @@ struct smb_version_operations {
        /* async read from the server */
        int (*async_readv)(struct cifs_readdata *);
        /* async write to the server */
-       int (*async_writev)(struct cifs_writedata *);
+       int (*async_writev)(struct cifs_writedata *,
+                           void (*release)(struct kref *));
        /* sync read from the server */
        int (*sync_read)(const unsigned int, struct cifsFileInfo *,
                         struct cifs_io_parms *, unsigned int *, char **,
@@ -395,6 +396,10 @@ struct smb_version_operations {
        int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
                        const char *, const void *, const __u16,
                        const struct nls_table *, int);
+       struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
+                       const char *, u32 *);
+       int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
+                       int);
 };
 
 struct smb_version_values {
@@ -1064,7 +1069,7 @@ struct cifs_writedata {
        unsigned int                    pagesz;
        unsigned int                    tailsz;
        unsigned int                    nr_pages;
-       struct page                     *pages[1];
+       struct page                     *pages[];
 };
 
 /*
index 79e6e9a93a8ce984420ef8dc68fa3d941ff1f045..d00e09dfc452a3b1c8aed81d4bc7e02a7a231424 100644 (file)
@@ -488,7 +488,8 @@ void cifs_readdata_release(struct kref *refcount);
 int cifs_async_readv(struct cifs_readdata *rdata);
 int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
 
-int cifs_async_writev(struct cifs_writedata *wdata);
+int cifs_async_writev(struct cifs_writedata *wdata,
+                     void (*release)(struct kref *kref));
 void cifs_writev_complete(struct work_struct *work);
 struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
                                                work_func_t complete);
index 4d881c35eecaa035717b52d9c19b9dac00dd9dae..f3264bd7a83d9427a158130a7d4a842443bd8b53 100644 (file)
@@ -1910,7 +1910,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
 
        do {
                server = tlink_tcon(wdata->cfile->tlink)->ses->server;
-               rc = server->ops->async_writev(wdata);
+               rc = server->ops->async_writev(wdata, cifs_writedata_release);
        } while (rc == -EAGAIN);
 
        for (i = 0; i < wdata->nr_pages; i++) {
@@ -1962,15 +1962,9 @@ cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
 {
        struct cifs_writedata *wdata;
 
-       /* this would overflow */
-       if (nr_pages == 0) {
-               cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
-               return NULL;
-       }
-
        /* writedata + number of page pointers */
        wdata = kzalloc(sizeof(*wdata) +
-                       sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
+                       sizeof(struct page *) * nr_pages, GFP_NOFS);
        if (wdata != NULL) {
                kref_init(&wdata->refcount);
                INIT_LIST_HEAD(&wdata->list);
@@ -2031,7 +2025,8 @@ cifs_writev_callback(struct mid_q_entry *mid)
 
 /* cifs_async_writev - send an async write, and set up mid to handle result */
 int
-cifs_async_writev(struct cifs_writedata *wdata)
+cifs_async_writev(struct cifs_writedata *wdata,
+                 void (*release)(struct kref *kref))
 {
        int rc = -EACCES;
        WRITE_REQ *smb = NULL;
@@ -2105,7 +2100,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
        if (rc == 0)
                cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
        else
-               kref_put(&wdata->refcount, cifs_writedata_release);
+               kref_put(&wdata->refcount, release);
 
 async_writev_out:
        cifs_small_buf_release(smb);
index a7eda8ebfacc8ca90210358b5e2300c7530e0223..755584684f6c51d0f9dc8444541017eca2d0b294 100644 (file)
@@ -2043,7 +2043,8 @@ static int cifs_writepages(struct address_space *mapping,
                        }
                        wdata->pid = wdata->cfile->pid;
                        server = tlink_tcon(wdata->cfile->tlink)->ses->server;
-                       rc = server->ops->async_writev(wdata);
+                       rc = server->ops->async_writev(wdata,
+                                                       cifs_writedata_release);
                } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
 
                for (i = 0; i < nr_pages; ++i)
@@ -2331,9 +2332,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
 }
 
 static void
-cifs_uncached_writev_complete(struct work_struct *work)
+cifs_uncached_writedata_release(struct kref *refcount)
 {
        int i;
+       struct cifs_writedata *wdata = container_of(refcount,
+                                       struct cifs_writedata, refcount);
+
+       for (i = 0; i < wdata->nr_pages; i++)
+               put_page(wdata->pages[i]);
+       cifs_writedata_release(refcount);
+}
+
+static void
+cifs_uncached_writev_complete(struct work_struct *work)
+{
        struct cifs_writedata *wdata = container_of(work,
                                        struct cifs_writedata, work);
        struct inode *inode = wdata->cfile->dentry->d_inode;
@@ -2347,12 +2359,7 @@ cifs_uncached_writev_complete(struct work_struct *work)
 
        complete(&wdata->done);
 
-       if (wdata->result != -EAGAIN) {
-               for (i = 0; i < wdata->nr_pages; i++)
-                       put_page(wdata->pages[i]);
-       }
-
-       kref_put(&wdata->refcount, cifs_writedata_release);
+       kref_put(&wdata->refcount, cifs_uncached_writedata_release);
 }
 
 /* attempt to send write to server, retry on any -EAGAIN errors */
@@ -2370,7 +2377,8 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
                        if (rc != 0)
                                continue;
                }
-               rc = server->ops->async_writev(wdata);
+               rc = server->ops->async_writev(wdata,
+                                              cifs_uncached_writedata_release);
        } while (rc == -EAGAIN);
 
        return rc;
@@ -2454,7 +2462,8 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
                wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
                rc = cifs_uncached_retry_writev(wdata);
                if (rc) {
-                       kref_put(&wdata->refcount, cifs_writedata_release);
+                       kref_put(&wdata->refcount,
+                                cifs_uncached_writedata_release);
                        break;
                }
 
@@ -2496,7 +2505,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
                        }
                }
                list_del_init(&wdata->list);
-               kref_put(&wdata->refcount, cifs_writedata_release);
+               kref_put(&wdata->refcount, cifs_uncached_writedata_release);
        }
 
        if (total_written > 0)
index 9cb9679d735719b42f83b89e39b9c0bbd56fdd65..be58b8fcdb3c321ffbab033a4a91abc76c774df3 100644 (file)
@@ -527,10 +527,15 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
                return PTR_ERR(tlink);
        tcon = tlink_tcon(tlink);
 
-       rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS",
-                           ea_value, 4 /* size of buf */, cifs_sb->local_nls,
-                           cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (tcon->ses->server->ops->query_all_EAs == NULL) {
+               cifs_put_tlink(tlink);
+               return -EOPNOTSUPP;
+       }
+
+       rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path,
+                       "SETFILEBITS", ea_value, 4 /* size of buf */,
+                       cifs_sb->local_nls,
+                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        cifs_put_tlink(tlink);
        if (rc < 0)
                return (int)rc;
index 9ac5bfc9cc56af6ee74f9f3d2e15e66ab2dd2e54..bfd66d84831eb827b93d8baa4f4b0c183dcdb084 100644 (file)
@@ -1067,6 +1067,14 @@ struct smb_version_operations smb1_operations = {
        .query_mf_symlink = cifs_query_mf_symlink,
        .create_mf_symlink = cifs_create_mf_symlink,
        .is_read_op = cifs_is_read_op,
+#ifdef CONFIG_CIFS_XATTR
+       .query_all_EAs = CIFSSMBQAllEAs,
+       .set_EA = CIFSSMBSetEA,
+#endif /* CIFS_XATTR */
+#ifdef CONFIG_CIFS_ACL
+       .get_acl = get_cifs_acl,
+       .set_acl = set_cifs_acl,
+#endif /* CIFS_ACL */
 };
 
 struct smb_version_values smb1_values = {
index 2013234b73adc47a5a34cb907ce0b818f65a16f5..a3f7a9c3cc69d81ef4ce58b8f509dda288fa6602 100644 (file)
@@ -1890,7 +1890,8 @@ smb2_writev_callback(struct mid_q_entry *mid)
 
 /* smb2_async_writev - send an async write, and set up mid to handle result */
 int
-smb2_async_writev(struct cifs_writedata *wdata)
+smb2_async_writev(struct cifs_writedata *wdata,
+                 void (*release)(struct kref *kref))
 {
        int rc = -EACCES;
        struct smb2_write_req *req = NULL;
@@ -1938,7 +1939,7 @@ smb2_async_writev(struct cifs_writedata *wdata)
                                smb2_writev_callback, wdata, 0);
 
        if (rc) {
-               kref_put(&wdata->refcount, cifs_writedata_release);
+               kref_put(&wdata->refcount, release);
                cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
        }
 
index 93adc64666f310345b4c6d76bba628741aa4e634..0ce48db20a6511add52f9b44f5cbf664a178e41f 100644 (file)
@@ -123,7 +123,8 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_async_readv(struct cifs_readdata *rdata);
 extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
                     unsigned int *nbytes, char **buf, int *buf_type);
-extern int smb2_async_writev(struct cifs_writedata *wdata);
+extern int smb2_async_writev(struct cifs_writedata *wdata,
+                            void (*release)(struct kref *kref));
 extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
                      unsigned int *nbytes, struct kvec *iov, int n_vec);
 extern int SMB2_echo(struct TCP_Server_Info *server);
index 95c43bb203353a65974a6cf5b24a0fe02c3c5c86..5ac836a86b1885d4e1766e831a1b56d3a263e277 100644 (file)
@@ -176,8 +176,12 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
                        rc = -ENOMEM;
                } else {
                        memcpy(pacl, ea_value, value_size);
-                       rc = set_cifs_acl(pacl, value_size,
-                               direntry->d_inode, full_path, CIFS_ACL_DACL);
+                       if (pTcon->ses->server->ops->set_acl)
+                               rc = pTcon->ses->server->ops->set_acl(pacl,
+                                               value_size, direntry->d_inode,
+                                               full_path, CIFS_ACL_DACL);
+                       else
+                               rc = -EOPNOTSUPP;
                        if (rc == 0) /* force revalidate of the inode */
                                CIFS_I(direntry->d_inode)->time = 0;
                        kfree(pacl);
@@ -323,8 +327,11 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
                        u32 acllen;
                        struct cifs_ntsd *pacl;
 
-                       pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
-                                               full_path, &acllen);
+                       if (pTcon->ses->server->ops->get_acl == NULL)
+                               goto get_ea_exit; /* rc already EOPNOTSUPP */
+
+                       pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
+                                       direntry->d_inode, full_path, &acllen);
                        if (IS_ERR(pacl)) {
                                rc = PTR_ERR(pacl);
                                cifs_dbg(VFS, "%s: error %zd getting sec desc\n",