Commit cbf2822a7d44352c5c4c15baf0da3a3dc8495e90

Authored by Linus Torvalds

Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6

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

Showing 10 changed files Side-by-side Diff

... ... @@ -1043,15 +1043,30 @@
1043 1043 __u32 secdesclen = 0;
1044 1044 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1045 1045 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
  1046 + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
  1047 + struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
  1048 + struct cifs_tcon *tcon;
1046 1049  
  1050 + if (IS_ERR(tlink))
  1051 + return PTR_ERR(tlink);
  1052 + tcon = tlink_tcon(tlink);
  1053 +
1047 1054 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
1048 1055  
1049 1056 /* Get the security descriptor */
1050   - pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
  1057 +
  1058 + if (tcon->ses->server->ops->get_acl == NULL) {
  1059 + cifs_put_tlink(tlink);
  1060 + return -EOPNOTSUPP;
  1061 + }
  1062 +
  1063 + pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
  1064 + &secdesclen);
1051 1065 if (IS_ERR(pntsd)) {
1052 1066 rc = PTR_ERR(pntsd);
1053 1067 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
1054   - goto out;
  1068 + cifs_put_tlink(tlink);
  1069 + return rc;
1055 1070 }
1056 1071  
1057 1072 /*
... ... @@ -1064,6 +1079,7 @@
1064 1079 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1065 1080 if (!pnntsd) {
1066 1081 kfree(pntsd);
  1082 + cifs_put_tlink(tlink);
1067 1083 return -ENOMEM;
1068 1084 }
1069 1085  
1070 1086  
1071 1087  
1072 1088  
... ... @@ -1072,15 +1088,19 @@
1072 1088  
1073 1089 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
1074 1090  
  1091 + if (tcon->ses->server->ops->set_acl == NULL)
  1092 + rc = -EOPNOTSUPP;
  1093 +
1075 1094 if (!rc) {
1076 1095 /* Set the security descriptor */
1077   - rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
  1096 + rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
  1097 + path, aclflag);
1078 1098 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
1079 1099 }
  1100 + cifs_put_tlink(tlink);
1080 1101  
1081 1102 kfree(pnntsd);
1082 1103 kfree(pntsd);
1083   -out:
1084 1104 return rc;
1085 1105 }
... ... @@ -323,7 +323,8 @@
323 323 /* async read from the server */
324 324 int (*async_readv)(struct cifs_readdata *);
325 325 /* async write to the server */
326   - int (*async_writev)(struct cifs_writedata *);
  326 + int (*async_writev)(struct cifs_writedata *,
  327 + void (*release)(struct kref *));
327 328 /* sync read from the server */
328 329 int (*sync_read)(const unsigned int, struct cifsFileInfo *,
329 330 struct cifs_io_parms *, unsigned int *, char **,
... ... @@ -395,6 +396,10 @@
395 396 int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
396 397 const char *, const void *, const __u16,
397 398 const struct nls_table *, int);
  399 + struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
  400 + const char *, u32 *);
  401 + int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
  402 + int);
398 403 };
399 404  
400 405 struct smb_version_values {
... ... @@ -1064,7 +1069,7 @@
1064 1069 unsigned int pagesz;
1065 1070 unsigned int tailsz;
1066 1071 unsigned int nr_pages;
1067   - struct page *pages[1];
  1072 + struct page *pages[];
1068 1073 };
1069 1074  
1070 1075 /*
... ... @@ -488,7 +488,8 @@
488 488 int cifs_async_readv(struct cifs_readdata *rdata);
489 489 int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
490 490  
491   -int cifs_async_writev(struct cifs_writedata *wdata);
  491 +int cifs_async_writev(struct cifs_writedata *wdata,
  492 + void (*release)(struct kref *kref));
492 493 void cifs_writev_complete(struct work_struct *work);
493 494 struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
494 495 work_func_t complete);
... ... @@ -1910,7 +1910,7 @@
1910 1910  
1911 1911 do {
1912 1912 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1913   - rc = server->ops->async_writev(wdata);
  1913 + rc = server->ops->async_writev(wdata, cifs_writedata_release);
1914 1914 } while (rc == -EAGAIN);
1915 1915  
1916 1916 for (i = 0; i < wdata->nr_pages; i++) {
1917 1917  
... ... @@ -1962,15 +1962,9 @@
1962 1962 {
1963 1963 struct cifs_writedata *wdata;
1964 1964  
1965   - /* this would overflow */
1966   - if (nr_pages == 0) {
1967   - cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
1968   - return NULL;
1969   - }
1970   -
1971 1965 /* writedata + number of page pointers */
1972 1966 wdata = kzalloc(sizeof(*wdata) +
1973   - sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
  1967 + sizeof(struct page *) * nr_pages, GFP_NOFS);
1974 1968 if (wdata != NULL) {
1975 1969 kref_init(&wdata->refcount);
1976 1970 INIT_LIST_HEAD(&wdata->list);
... ... @@ -2031,7 +2025,8 @@
2031 2025  
2032 2026 /* cifs_async_writev - send an async write, and set up mid to handle result */
2033 2027 int
2034   -cifs_async_writev(struct cifs_writedata *wdata)
  2028 +cifs_async_writev(struct cifs_writedata *wdata,
  2029 + void (*release)(struct kref *kref))
2035 2030 {
2036 2031 int rc = -EACCES;
2037 2032 WRITE_REQ *smb = NULL;
... ... @@ -2105,7 +2100,7 @@
2105 2100 if (rc == 0)
2106 2101 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
2107 2102 else
2108   - kref_put(&wdata->refcount, cifs_writedata_release);
  2103 + kref_put(&wdata->refcount, release);
2109 2104  
2110 2105 async_writev_out:
2111 2106 cifs_small_buf_release(smb);
... ... @@ -2043,7 +2043,8 @@
2043 2043 }
2044 2044 wdata->pid = wdata->cfile->pid;
2045 2045 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
2046   - rc = server->ops->async_writev(wdata);
  2046 + rc = server->ops->async_writev(wdata,
  2047 + cifs_writedata_release);
2047 2048 } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
2048 2049  
2049 2050 for (i = 0; i < nr_pages; ++i)
2050 2051  
... ... @@ -2331,9 +2332,20 @@
2331 2332 }
2332 2333  
2333 2334 static void
2334   -cifs_uncached_writev_complete(struct work_struct *work)
  2335 +cifs_uncached_writedata_release(struct kref *refcount)
2335 2336 {
2336 2337 int i;
  2338 + struct cifs_writedata *wdata = container_of(refcount,
  2339 + struct cifs_writedata, refcount);
  2340 +
  2341 + for (i = 0; i < wdata->nr_pages; i++)
  2342 + put_page(wdata->pages[i]);
  2343 + cifs_writedata_release(refcount);
  2344 +}
  2345 +
  2346 +static void
  2347 +cifs_uncached_writev_complete(struct work_struct *work)
  2348 +{
2337 2349 struct cifs_writedata *wdata = container_of(work,
2338 2350 struct cifs_writedata, work);
2339 2351 struct inode *inode = wdata->cfile->dentry->d_inode;
... ... @@ -2347,12 +2359,7 @@
2347 2359  
2348 2360 complete(&wdata->done);
2349 2361  
2350   - if (wdata->result != -EAGAIN) {
2351   - for (i = 0; i < wdata->nr_pages; i++)
2352   - put_page(wdata->pages[i]);
2353   - }
2354   -
2355   - kref_put(&wdata->refcount, cifs_writedata_release);
  2362 + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
2356 2363 }
2357 2364  
2358 2365 /* attempt to send write to server, retry on any -EAGAIN errors */
... ... @@ -2370,7 +2377,8 @@
2370 2377 if (rc != 0)
2371 2378 continue;
2372 2379 }
2373   - rc = server->ops->async_writev(wdata);
  2380 + rc = server->ops->async_writev(wdata,
  2381 + cifs_uncached_writedata_release);
2374 2382 } while (rc == -EAGAIN);
2375 2383  
2376 2384 return rc;
... ... @@ -2454,7 +2462,8 @@
2454 2462 wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
2455 2463 rc = cifs_uncached_retry_writev(wdata);
2456 2464 if (rc) {
2457   - kref_put(&wdata->refcount, cifs_writedata_release);
  2465 + kref_put(&wdata->refcount,
  2466 + cifs_uncached_writedata_release);
2458 2467 break;
2459 2468 }
2460 2469  
... ... @@ -2496,7 +2505,7 @@
2496 2505 }
2497 2506 }
2498 2507 list_del_init(&wdata->list);
2499   - kref_put(&wdata->refcount, cifs_writedata_release);
  2508 + kref_put(&wdata->refcount, cifs_uncached_writedata_release);
2500 2509 }
2501 2510  
2502 2511 if (total_written > 0)
... ... @@ -527,10 +527,15 @@
527 527 return PTR_ERR(tlink);
528 528 tcon = tlink_tcon(tlink);
529 529  
530   - rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS",
531   - ea_value, 4 /* size of buf */, cifs_sb->local_nls,
532   - cifs_sb->mnt_cifs_flags &
533   - CIFS_MOUNT_MAP_SPECIAL_CHR);
  530 + if (tcon->ses->server->ops->query_all_EAs == NULL) {
  531 + cifs_put_tlink(tlink);
  532 + return -EOPNOTSUPP;
  533 + }
  534 +
  535 + rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path,
  536 + "SETFILEBITS", ea_value, 4 /* size of buf */,
  537 + cifs_sb->local_nls,
  538 + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
534 539 cifs_put_tlink(tlink);
535 540 if (rc < 0)
536 541 return (int)rc;
... ... @@ -1067,6 +1067,14 @@
1067 1067 .query_mf_symlink = cifs_query_mf_symlink,
1068 1068 .create_mf_symlink = cifs_create_mf_symlink,
1069 1069 .is_read_op = cifs_is_read_op,
  1070 +#ifdef CONFIG_CIFS_XATTR
  1071 + .query_all_EAs = CIFSSMBQAllEAs,
  1072 + .set_EA = CIFSSMBSetEA,
  1073 +#endif /* CIFS_XATTR */
  1074 +#ifdef CONFIG_CIFS_ACL
  1075 + .get_acl = get_cifs_acl,
  1076 + .set_acl = set_cifs_acl,
  1077 +#endif /* CIFS_ACL */
1070 1078 };
1071 1079  
1072 1080 struct smb_version_values smb1_values = {
... ... @@ -1890,7 +1890,8 @@
1890 1890  
1891 1891 /* smb2_async_writev - send an async write, and set up mid to handle result */
1892 1892 int
1893   -smb2_async_writev(struct cifs_writedata *wdata)
  1893 +smb2_async_writev(struct cifs_writedata *wdata,
  1894 + void (*release)(struct kref *kref))
1894 1895 {
1895 1896 int rc = -EACCES;
1896 1897 struct smb2_write_req *req = NULL;
... ... @@ -1938,7 +1939,7 @@
1938 1939 smb2_writev_callback, wdata, 0);
1939 1940  
1940 1941 if (rc) {
1941   - kref_put(&wdata->refcount, cifs_writedata_release);
  1942 + kref_put(&wdata->refcount, release);
1942 1943 cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
1943 1944 }
1944 1945  
... ... @@ -123,7 +123,8 @@
123 123 extern int smb2_async_readv(struct cifs_readdata *rdata);
124 124 extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
125 125 unsigned int *nbytes, char **buf, int *buf_type);
126   -extern int smb2_async_writev(struct cifs_writedata *wdata);
  126 +extern int smb2_async_writev(struct cifs_writedata *wdata,
  127 + void (*release)(struct kref *kref));
127 128 extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
128 129 unsigned int *nbytes, struct kvec *iov, int n_vec);
129 130 extern int SMB2_echo(struct TCP_Server_Info *server);
... ... @@ -176,8 +176,12 @@
176 176 rc = -ENOMEM;
177 177 } else {
178 178 memcpy(pacl, ea_value, value_size);
179   - rc = set_cifs_acl(pacl, value_size,
180   - direntry->d_inode, full_path, CIFS_ACL_DACL);
  179 + if (pTcon->ses->server->ops->set_acl)
  180 + rc = pTcon->ses->server->ops->set_acl(pacl,
  181 + value_size, direntry->d_inode,
  182 + full_path, CIFS_ACL_DACL);
  183 + else
  184 + rc = -EOPNOTSUPP;
181 185 if (rc == 0) /* force revalidate of the inode */
182 186 CIFS_I(direntry->d_inode)->time = 0;
183 187 kfree(pacl);
... ... @@ -323,8 +327,11 @@
323 327 u32 acllen;
324 328 struct cifs_ntsd *pacl;
325 329  
326   - pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
327   - full_path, &acllen);
  330 + if (pTcon->ses->server->ops->get_acl == NULL)
  331 + goto get_ea_exit; /* rc already EOPNOTSUPP */
  332 +
  333 + pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
  334 + direntry->d_inode, full_path, &acllen);
328 335 if (IS_ERR(pacl)) {
329 336 rc = PTR_ERR(pacl);
330 337 cifs_dbg(VFS, "%s: error %zd getting sec desc\n",