Commit cbf2822a7d44352c5c4c15baf0da3a3dc8495e90
Exists in
master
and in
16 other branches
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
fs/cifs/cifsacl.c
... | ... | @@ -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 | } |
fs/cifs/cifsglob.h
... | ... | @@ -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 | /* |
fs/cifs/cifsproto.h
... | ... | @@ -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); |
fs/cifs/cifssmb.c
... | ... | @@ -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); |
fs/cifs/file.c
... | ... | @@ -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) |
fs/cifs/inode.c
... | ... | @@ -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; |
fs/cifs/smb1ops.c
... | ... | @@ -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 = { |
fs/cifs/smb2pdu.c
... | ... | @@ -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 |
fs/cifs/smb2proto.h
... | ... | @@ -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); |
fs/cifs/xattr.c
... | ... | @@ -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", |