Skip to content

Commit cbf2822

Browse files
committed
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
2 parents b28a960 + 4a5c80d commit cbf2822

File tree

10 files changed

+91
-39
lines changed

10 files changed

+91
-39
lines changed

fs/cifs/cifsacl.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,15 +1043,30 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
10431043
__u32 secdesclen = 0;
10441044
struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
10451045
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;
1049+
1050+
if (IS_ERR(tlink))
1051+
return PTR_ERR(tlink);
1052+
tcon = tlink_tcon(tlink);
10461053

10471054
cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
10481055

10491056
/* 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);
10511065
if (IS_ERR(pntsd)) {
10521066
rc = PTR_ERR(pntsd);
10531067
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
1054-
goto out;
1068+
cifs_put_tlink(tlink);
1069+
return rc;
10551070
}
10561071

10571072
/*
@@ -1064,6 +1079,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
10641079
pnntsd = kmalloc(secdesclen, GFP_KERNEL);
10651080
if (!pnntsd) {
10661081
kfree(pntsd);
1082+
cifs_put_tlink(tlink);
10671083
return -ENOMEM;
10681084
}
10691085

@@ -1072,14 +1088,18 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
10721088

10731089
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
10741090

1091+
if (tcon->ses->server->ops->set_acl == NULL)
1092+
rc = -EOPNOTSUPP;
1093+
10751094
if (!rc) {
10761095
/* 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);
10781098
cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
10791099
}
1100+
cifs_put_tlink(tlink);
10801101

10811102
kfree(pnntsd);
10821103
kfree(pntsd);
1083-
out:
10841104
return rc;
10851105
}

fs/cifs/cifsglob.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,8 @@ struct smb_version_operations {
323323
/* async read from the server */
324324
int (*async_readv)(struct cifs_readdata *);
325325
/* async write to the server */
326-
int (*async_writev)(struct cifs_writedata *);
326+
int (*async_writev)(struct cifs_writedata *,
327+
void (*release)(struct kref *));
327328
/* sync read from the server */
328329
int (*sync_read)(const unsigned int, struct cifsFileInfo *,
329330
struct cifs_io_parms *, unsigned int *, char **,
@@ -395,6 +396,10 @@ struct smb_version_operations {
395396
int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
396397
const char *, const void *, const __u16,
397398
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);
398403
};
399404

400405
struct smb_version_values {
@@ -1064,7 +1069,7 @@ struct cifs_writedata {
10641069
unsigned int pagesz;
10651070
unsigned int tailsz;
10661071
unsigned int nr_pages;
1067-
struct page *pages[1];
1072+
struct page *pages[];
10681073
};
10691074

10701075
/*

fs/cifs/cifsproto.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,8 @@ void cifs_readdata_release(struct kref *refcount);
488488
int cifs_async_readv(struct cifs_readdata *rdata);
489489
int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
490490

491-
int cifs_async_writev(struct cifs_writedata *wdata);
491+
int cifs_async_writev(struct cifs_writedata *wdata,
492+
void (*release)(struct kref *kref));
492493
void cifs_writev_complete(struct work_struct *work);
493494
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
494495
work_func_t complete);

fs/cifs/cifssmb.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,7 +1910,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
19101910

19111911
do {
19121912
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);
19141914
} while (rc == -EAGAIN);
19151915

19161916
for (i = 0; i < wdata->nr_pages; i++) {
@@ -1962,15 +1962,9 @@ cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
19621962
{
19631963
struct cifs_writedata *wdata;
19641964

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-
19711965
/* writedata + number of page pointers */
19721966
wdata = kzalloc(sizeof(*wdata) +
1973-
sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1967+
sizeof(struct page *) * nr_pages, GFP_NOFS);
19741968
if (wdata != NULL) {
19751969
kref_init(&wdata->refcount);
19761970
INIT_LIST_HEAD(&wdata->list);
@@ -2031,7 +2025,8 @@ cifs_writev_callback(struct mid_q_entry *mid)
20312025

20322026
/* cifs_async_writev - send an async write, and set up mid to handle result */
20332027
int
2034-
cifs_async_writev(struct cifs_writedata *wdata)
2028+
cifs_async_writev(struct cifs_writedata *wdata,
2029+
void (*release)(struct kref *kref))
20352030
{
20362031
int rc = -EACCES;
20372032
WRITE_REQ *smb = NULL;
@@ -2105,7 +2100,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
21052100
if (rc == 0)
21062101
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
21072102
else
2108-
kref_put(&wdata->refcount, cifs_writedata_release);
2103+
kref_put(&wdata->refcount, release);
21092104

21102105
async_writev_out:
21112106
cifs_small_buf_release(smb);

fs/cifs/file.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,7 +2043,8 @@ static int cifs_writepages(struct address_space *mapping,
20432043
}
20442044
wdata->pid = wdata->cfile->pid;
20452045
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);
20472048
} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
20482049

20492050
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)
23312332
}
23322333

23332334
static void
2334-
cifs_uncached_writev_complete(struct work_struct *work)
2335+
cifs_uncached_writedata_release(struct kref *refcount)
23352336
{
23362337
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+
{
23372349
struct cifs_writedata *wdata = container_of(work,
23382350
struct cifs_writedata, work);
23392351
struct inode *inode = wdata->cfile->dentry->d_inode;
@@ -2347,12 +2359,7 @@ cifs_uncached_writev_complete(struct work_struct *work)
23472359

23482360
complete(&wdata->done);
23492361

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);
23562363
}
23572364

23582365
/* attempt to send write to server, retry on any -EAGAIN errors */
@@ -2370,7 +2377,8 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
23702377
if (rc != 0)
23712378
continue;
23722379
}
2373-
rc = server->ops->async_writev(wdata);
2380+
rc = server->ops->async_writev(wdata,
2381+
cifs_uncached_writedata_release);
23742382
} while (rc == -EAGAIN);
23752383

23762384
return rc;
@@ -2454,7 +2462,8 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
24542462
wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
24552463
rc = cifs_uncached_retry_writev(wdata);
24562464
if (rc) {
2457-
kref_put(&wdata->refcount, cifs_writedata_release);
2465+
kref_put(&wdata->refcount,
2466+
cifs_uncached_writedata_release);
24582467
break;
24592468
}
24602469

@@ -2496,7 +2505,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
24962505
}
24972506
}
24982507
list_del_init(&wdata->list);
2499-
kref_put(&wdata->refcount, cifs_writedata_release);
2508+
kref_put(&wdata->refcount, cifs_uncached_writedata_release);
25002509
}
25012510

25022511
if (total_written > 0)

fs/cifs/inode.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -527,10 +527,15 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
527527
return PTR_ERR(tlink);
528528
tcon = tlink_tcon(tlink);
529529

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);
534539
cifs_put_tlink(tlink);
535540
if (rc < 0)
536541
return (int)rc;

fs/cifs/smb1ops.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,14 @@ struct smb_version_operations smb1_operations = {
10671067
.query_mf_symlink = cifs_query_mf_symlink,
10681068
.create_mf_symlink = cifs_create_mf_symlink,
10691069
.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 */
10701078
};
10711079

10721080
struct smb_version_values smb1_values = {

fs/cifs/smb2pdu.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,7 +1890,8 @@ smb2_writev_callback(struct mid_q_entry *mid)
18901890

18911891
/* smb2_async_writev - send an async write, and set up mid to handle result */
18921892
int
1893-
smb2_async_writev(struct cifs_writedata *wdata)
1893+
smb2_async_writev(struct cifs_writedata *wdata,
1894+
void (*release)(struct kref *kref))
18941895
{
18951896
int rc = -EACCES;
18961897
struct smb2_write_req *req = NULL;
@@ -1938,7 +1939,7 @@ smb2_async_writev(struct cifs_writedata *wdata)
19381939
smb2_writev_callback, wdata, 0);
19391940

19401941
if (rc) {
1941-
kref_put(&wdata->refcount, cifs_writedata_release);
1942+
kref_put(&wdata->refcount, release);
19421943
cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
19431944
}
19441945

fs/cifs/smb2proto.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
123123
extern int smb2_async_readv(struct cifs_readdata *rdata);
124124
extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
125125
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));
127128
extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
128129
unsigned int *nbytes, struct kvec *iov, int n_vec);
129130
extern int SMB2_echo(struct TCP_Server_Info *server);

fs/cifs/xattr.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,12 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
176176
rc = -ENOMEM;
177177
} else {
178178
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;
181185
if (rc == 0) /* force revalidate of the inode */
182186
CIFS_I(direntry->d_inode)->time = 0;
183187
kfree(pacl);
@@ -323,8 +327,11 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
323327
u32 acllen;
324328
struct cifs_ntsd *pacl;
325329

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);
328335
if (IS_ERR(pacl)) {
329336
rc = PTR_ERR(pacl);
330337
cifs_dbg(VFS, "%s: error %zd getting sec desc\n",

0 commit comments

Comments
 (0)