Skip to content

Commit 0f9d140

Browse files
committed
Merge tag '5.0-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: "A set of cifs/smb3 fixes, 4 for stable, most from Pavel. His patches fix an important set of crediting (flow control) problems, and also two problems in cifs_writepages, ddressing some large i/o and also compounding issues" * tag '5.0-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: update internal module version number CIFS: Fix error paths in writeback code CIFS: Move credit processing to mid callbacks for SMB3 CIFS: Fix credits calculation for cancelled requests cifs: Fix potential OOB access of lock element array cifs: Limit memory used by lock request calls to a page cifs: move large array from stack to heap CIFS: Do not hide EINTR after sending network packets CIFS: Fix credit computation for compounded requests CIFS: Do not set credits to 1 if the server didn't grant anything CIFS: Fix adjustment of credits for MTU requests cifs: Fix a tiny potential memory leak cifs: Fix a debug message
2 parents e170672 + 48d2ba6 commit 0f9d140

File tree

10 files changed

+211
-65
lines changed

10 files changed

+211
-65
lines changed

fs/cifs/cifsfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
150150
extern const struct export_operations cifs_export_ops;
151151
#endif /* CONFIG_CIFS_NFSD_EXPORT */
152152

153-
#define CIFS_VERSION "2.15"
153+
#define CIFS_VERSION "2.16"
154154
#endif /* _CIFSFS_H */

fs/cifs/cifsglob.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,7 @@ struct mid_q_entry {
14381438
int mid_state; /* wish this were enum but can not pass to wait_event */
14391439
unsigned int mid_flags;
14401440
__le16 command; /* smb command code */
1441+
unsigned int optype; /* operation type */
14411442
bool large_buf:1; /* if valid response, is pointer to large buf */
14421443
bool multiRsp:1; /* multiple trans2 responses for one request */
14431444
bool multiEnd:1; /* both received */
@@ -1574,6 +1575,25 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
15741575
kfree(param);
15751576
}
15761577

1578+
static inline bool is_interrupt_error(int error)
1579+
{
1580+
switch (error) {
1581+
case -EINTR:
1582+
case -ERESTARTSYS:
1583+
case -ERESTARTNOHAND:
1584+
case -ERESTARTNOINTR:
1585+
return true;
1586+
}
1587+
return false;
1588+
}
1589+
1590+
static inline bool is_retryable_error(int error)
1591+
{
1592+
if (is_interrupt_error(error) || error == -EAGAIN)
1593+
return true;
1594+
return false;
1595+
}
1596+
15771597
#define MID_FREE 0
15781598
#define MID_REQUEST_ALLOCATED 1
15791599
#define MID_REQUEST_SUBMITTED 2

fs/cifs/cifssmb.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,24 +128,31 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
128128
int rc;
129129
struct dfs_cache_tgt_list tl;
130130
struct dfs_cache_tgt_iterator *it = NULL;
131-
char tree[MAX_TREE_SIZE + 1];
131+
char *tree;
132132
const char *tcp_host;
133133
size_t tcp_host_len;
134134
const char *dfs_host;
135135
size_t dfs_host_len;
136136

137+
tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
138+
if (!tree)
139+
return -ENOMEM;
140+
137141
if (tcon->ipc) {
138-
snprintf(tree, sizeof(tree), "\\\\%s\\IPC$",
142+
snprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
139143
tcon->ses->server->hostname);
140-
return CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
144+
rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
145+
goto out;
141146
}
142147

143-
if (!tcon->dfs_path)
144-
return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
148+
if (!tcon->dfs_path) {
149+
rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
150+
goto out;
151+
}
145152

146153
rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
147154
if (rc)
148-
return rc;
155+
goto out;
149156

150157
extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
151158
&tcp_host_len);
@@ -165,7 +172,7 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
165172
continue;
166173
}
167174

168-
snprintf(tree, sizeof(tree), "\\%s", tgt);
175+
snprintf(tree, MAX_TREE_SIZE, "\\%s", tgt);
169176

170177
rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
171178
if (!rc)
@@ -182,6 +189,8 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
182189
rc = -ENOENT;
183190
}
184191
dfs_cache_free_tgts(&tl);
192+
out:
193+
kfree(tree);
185194
return rc;
186195
}
187196
#else
@@ -2114,7 +2123,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
21142123

21152124
for (j = 0; j < nr_pages; j++) {
21162125
unlock_page(wdata2->pages[j]);
2117-
if (rc != 0 && rc != -EAGAIN) {
2126+
if (rc != 0 && !is_retryable_error(rc)) {
21182127
SetPageError(wdata2->pages[j]);
21192128
end_page_writeback(wdata2->pages[j]);
21202129
put_page(wdata2->pages[j]);
@@ -2123,7 +2132,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
21232132

21242133
if (rc) {
21252134
kref_put(&wdata2->refcount, cifs_writedata_release);
2126-
if (rc == -EAGAIN)
2135+
if (is_retryable_error(rc))
21272136
continue;
21282137
break;
21292138
}
@@ -2132,7 +2141,8 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
21322141
i += nr_pages;
21332142
} while (i < wdata->nr_pages);
21342143

2135-
mapping_set_error(inode->i_mapping, rc);
2144+
if (rc != 0 && !is_retryable_error(rc))
2145+
mapping_set_error(inode->i_mapping, rc);
21362146
kref_put(&wdata->refcount, cifs_writedata_release);
21372147
}
21382148

fs/cifs/connect.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,10 @@ static void reconn_inval_dfs_target(struct TCP_Server_Info *server,
433433
kfree(server->hostname);
434434

435435
server->hostname = extract_hostname(name);
436-
if (!server->hostname) {
437-
cifs_dbg(FYI, "%s: failed to extract hostname from target: %d\n",
438-
__func__, -ENOMEM);
436+
if (IS_ERR(server->hostname)) {
437+
cifs_dbg(FYI,
438+
"%s: failed to extract hostname from target: %ld\n",
439+
__func__, PTR_ERR(server->hostname));
439440
}
440441
}
441442

fs/cifs/dfs_cache.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ static int get_tgt_list(const struct dfs_cache_entry *ce,
776776
it->it_name = kstrndup(t->t_name, strlen(t->t_name),
777777
GFP_KERNEL);
778778
if (!it->it_name) {
779+
kfree(it);
779780
rc = -ENOMEM;
780781
goto err_free_it;
781782
}

fs/cifs/file.c

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
733733

734734
if (can_flush) {
735735
rc = filemap_write_and_wait(inode->i_mapping);
736-
mapping_set_error(inode->i_mapping, rc);
736+
if (!is_interrupt_error(rc))
737+
mapping_set_error(inode->i_mapping, rc);
737738

738739
if (tcon->unix_ext)
739740
rc = cifs_get_inode_info_unix(&inode, full_path,
@@ -1132,14 +1133,18 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
11321133

11331134
/*
11341135
* Accessing maxBuf is racy with cifs_reconnect - need to store value
1135-
* and check it for zero before using.
1136+
* and check it before using.
11361137
*/
11371138
max_buf = tcon->ses->server->maxBuf;
1138-
if (!max_buf) {
1139+
if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE))) {
11391140
free_xid(xid);
11401141
return -EINVAL;
11411142
}
11421143

1144+
BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) >
1145+
PAGE_SIZE);
1146+
max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr),
1147+
PAGE_SIZE);
11431148
max_num = (max_buf - sizeof(struct smb_hdr)) /
11441149
sizeof(LOCKING_ANDX_RANGE);
11451150
buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
@@ -1472,12 +1477,16 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
14721477

14731478
/*
14741479
* Accessing maxBuf is racy with cifs_reconnect - need to store value
1475-
* and check it for zero before using.
1480+
* and check it before using.
14761481
*/
14771482
max_buf = tcon->ses->server->maxBuf;
1478-
if (!max_buf)
1483+
if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE)))
14791484
return -EINVAL;
14801485

1486+
BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) >
1487+
PAGE_SIZE);
1488+
max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr),
1489+
PAGE_SIZE);
14811490
max_num = (max_buf - sizeof(struct smb_hdr)) /
14821491
sizeof(LOCKING_ANDX_RANGE);
14831492
buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
@@ -2110,6 +2119,7 @@ static int cifs_writepages(struct address_space *mapping,
21102119
pgoff_t end, index;
21112120
struct cifs_writedata *wdata;
21122121
int rc = 0;
2122+
int saved_rc = 0;
21132123
unsigned int xid;
21142124

21152125
/*
@@ -2138,15 +2148,18 @@ static int cifs_writepages(struct address_space *mapping,
21382148

21392149
rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize,
21402150
&wsize, &credits);
2141-
if (rc)
2151+
if (rc != 0) {
2152+
done = true;
21422153
break;
2154+
}
21432155

21442156
tofind = min((wsize / PAGE_SIZE) - 1, end - index) + 1;
21452157

21462158
wdata = wdata_alloc_and_fillpages(tofind, mapping, end, &index,
21472159
&found_pages);
21482160
if (!wdata) {
21492161
rc = -ENOMEM;
2162+
done = true;
21502163
add_credits_and_wake_if(server, credits, 0);
21512164
break;
21522165
}
@@ -2175,15 +2188,15 @@ static int cifs_writepages(struct address_space *mapping,
21752188
if (rc != 0) {
21762189
add_credits_and_wake_if(server, wdata->credits, 0);
21772190
for (i = 0; i < nr_pages; ++i) {
2178-
if (rc == -EAGAIN)
2191+
if (is_retryable_error(rc))
21792192
redirty_page_for_writepage(wbc,
21802193
wdata->pages[i]);
21812194
else
21822195
SetPageError(wdata->pages[i]);
21832196
end_page_writeback(wdata->pages[i]);
21842197
put_page(wdata->pages[i]);
21852198
}
2186-
if (rc != -EAGAIN)
2199+
if (!is_retryable_error(rc))
21872200
mapping_set_error(mapping, rc);
21882201
}
21892202
kref_put(&wdata->refcount, cifs_writedata_release);
@@ -2193,6 +2206,15 @@ static int cifs_writepages(struct address_space *mapping,
21932206
continue;
21942207
}
21952208

2209+
/* Return immediately if we received a signal during writing */
2210+
if (is_interrupt_error(rc)) {
2211+
done = true;
2212+
break;
2213+
}
2214+
2215+
if (rc != 0 && saved_rc == 0)
2216+
saved_rc = rc;
2217+
21962218
wbc->nr_to_write -= nr_pages;
21972219
if (wbc->nr_to_write <= 0)
21982220
done = true;
@@ -2210,6 +2232,9 @@ static int cifs_writepages(struct address_space *mapping,
22102232
goto retry;
22112233
}
22122234

2235+
if (saved_rc != 0)
2236+
rc = saved_rc;
2237+
22132238
if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
22142239
mapping->writeback_index = index;
22152240

@@ -2242,8 +2267,8 @@ cifs_writepage_locked(struct page *page, struct writeback_control *wbc)
22422267
set_page_writeback(page);
22432268
retry_write:
22442269
rc = cifs_partialpagewrite(page, 0, PAGE_SIZE);
2245-
if (rc == -EAGAIN) {
2246-
if (wbc->sync_mode == WB_SYNC_ALL)
2270+
if (is_retryable_error(rc)) {
2271+
if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
22472272
goto retry_write;
22482273
redirty_page_for_writepage(wbc, page);
22492274
} else if (rc != 0) {

fs/cifs/inode.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2257,6 +2257,11 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
22572257
* the flush returns error?
22582258
*/
22592259
rc = filemap_write_and_wait(inode->i_mapping);
2260+
if (is_interrupt_error(rc)) {
2261+
rc = -ERESTARTSYS;
2262+
goto out;
2263+
}
2264+
22602265
mapping_set_error(inode->i_mapping, rc);
22612266
rc = 0;
22622267

@@ -2400,6 +2405,11 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
24002405
* the flush returns error?
24012406
*/
24022407
rc = filemap_write_and_wait(inode->i_mapping);
2408+
if (is_interrupt_error(rc)) {
2409+
rc = -ERESTARTSYS;
2410+
goto cifs_setattr_exit;
2411+
}
2412+
24032413
mapping_set_error(inode->i_mapping, rc);
24042414
rc = 0;
24052415

fs/cifs/smb2file.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,14 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
122122

123123
/*
124124
* Accessing maxBuf is racy with cifs_reconnect - need to store value
125-
* and check it for zero before using.
125+
* and check it before using.
126126
*/
127127
max_buf = tcon->ses->server->maxBuf;
128-
if (!max_buf)
128+
if (max_buf < sizeof(struct smb2_lock_element))
129129
return -EINVAL;
130130

131+
BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
132+
max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
131133
max_num = max_buf / sizeof(struct smb2_lock_element);
132134
buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
133135
if (!buf)
@@ -264,6 +266,8 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
264266
return -EINVAL;
265267
}
266268

269+
BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
270+
max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
267271
max_num = max_buf / sizeof(struct smb2_lock_element);
268272
buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
269273
if (!buf) {

0 commit comments

Comments
 (0)