aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-18 12:28:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-18 12:28:11 -0400
commita9866ba47c3e7b7665b5f08fa6ef684f3285c939 (patch)
tree1d3977c467148892532f683ac5fcc4534c672b5d
parent331ae4962b975246944ea039697a8f1cadce42bb (diff)
parentcd60042cc1392e79410dc8de9e9c1abb38a29e57 (diff)
Merge git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French. * git://git.samba.org/sfrench/cifs-2.6: cifs: always update the inode cache with the results from a FIND_* cifs: when CONFIG_HIGHMEM is set, serialize the read/write kmaps cifs: on CONFIG_HIGHMEM machines, limit the rsize/wsize to the kmap space Initialise mid_q_entry before putting it on the pending queue
-rw-r--r--fs/cifs/cifssmb.c30
-rw-r--r--fs/cifs/connect.c18
-rw-r--r--fs/cifs/readdir.c7
-rw-r--r--fs/cifs/transport.c26
4 files changed, 66 insertions, 15 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 5b400730c213..4ee522b3f66f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -86,7 +86,31 @@ static struct {
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */ 86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */ 87#endif /* CIFS_POSIX */
88 88
89/* Forward declarations */ 89#ifdef CONFIG_HIGHMEM
90/*
91 * On arches that have high memory, kmap address space is limited. By
92 * serializing the kmap operations on those arches, we ensure that we don't
93 * end up with a bunch of threads in writeback with partially mapped page
94 * arrays, stuck waiting for kmap to come back. That situation prevents
95 * progress and can deadlock.
96 */
97static DEFINE_MUTEX(cifs_kmap_mutex);
98
99static inline void
100cifs_kmap_lock(void)
101{
102 mutex_lock(&cifs_kmap_mutex);
103}
104
105static inline void
106cifs_kmap_unlock(void)
107{
108 mutex_unlock(&cifs_kmap_mutex);
109}
110#else /* !CONFIG_HIGHMEM */
111#define cifs_kmap_lock() do { ; } while(0)
112#define cifs_kmap_unlock() do { ; } while(0)
113#endif /* CONFIG_HIGHMEM */
90 114
91/* Mark as invalid, all open files on tree connections since they 115/* Mark as invalid, all open files on tree connections since they
92 were closed when session to server was lost */ 116 were closed when session to server was lost */
@@ -1503,7 +1527,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1503 } 1527 }
1504 1528
1505 /* marshal up the page array */ 1529 /* marshal up the page array */
1530 cifs_kmap_lock();
1506 len = rdata->marshal_iov(rdata, data_len); 1531 len = rdata->marshal_iov(rdata, data_len);
1532 cifs_kmap_unlock();
1507 data_len -= len; 1533 data_len -= len;
1508 1534
1509 /* issue the read if we have any iovecs left to fill */ 1535 /* issue the read if we have any iovecs left to fill */
@@ -2069,7 +2095,9 @@ cifs_async_writev(struct cifs_writedata *wdata)
2069 * and set the iov_len properly for each one. It may also set 2095 * and set the iov_len properly for each one. It may also set
2070 * wdata->bytes too. 2096 * wdata->bytes too.
2071 */ 2097 */
2098 cifs_kmap_lock();
2072 wdata->marshal_iov(iov, wdata); 2099 wdata->marshal_iov(iov, wdata);
2100 cifs_kmap_unlock();
2073 2101
2074 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes); 2102 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2075 2103
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 0ae86ddf2213..94b7788c3189 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3445,6 +3445,18 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
3445#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024) 3445#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
3446#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536) 3446#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
3447 3447
3448/*
3449 * On hosts with high memory, we can't currently support wsize/rsize that are
3450 * larger than we can kmap at once. Cap the rsize/wsize at
3451 * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
3452 * larger than that anyway.
3453 */
3454#ifdef CONFIG_HIGHMEM
3455#define CIFS_KMAP_SIZE_LIMIT (LAST_PKMAP * PAGE_CACHE_SIZE)
3456#else /* CONFIG_HIGHMEM */
3457#define CIFS_KMAP_SIZE_LIMIT (1<<24)
3458#endif /* CONFIG_HIGHMEM */
3459
3448static unsigned int 3460static unsigned int
3449cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) 3461cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
3450{ 3462{
@@ -3475,6 +3487,9 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
3475 wsize = min_t(unsigned int, wsize, 3487 wsize = min_t(unsigned int, wsize,
3476 server->maxBuf - sizeof(WRITE_REQ) + 4); 3488 server->maxBuf - sizeof(WRITE_REQ) + 4);
3477 3489
3490 /* limit to the amount that we can kmap at once */
3491 wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
3492
3478 /* hard limit of CIFS_MAX_WSIZE */ 3493 /* hard limit of CIFS_MAX_WSIZE */
3479 wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); 3494 wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
3480 3495
@@ -3516,6 +3531,9 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
3516 if (!(server->capabilities & CAP_LARGE_READ_X)) 3531 if (!(server->capabilities & CAP_LARGE_READ_X))
3517 rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); 3532 rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
3518 3533
3534 /* limit to the amount that we can kmap at once */
3535 rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
3536
3519 /* hard limit of CIFS_MAX_RSIZE */ 3537 /* hard limit of CIFS_MAX_RSIZE */
3520 rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); 3538 rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
3521 3539
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 0a8224d1c4c5..a4217f02fab2 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -86,9 +86,12 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
86 86
87 dentry = d_lookup(parent, name); 87 dentry = d_lookup(parent, name);
88 if (dentry) { 88 if (dentry) {
89 /* FIXME: check for inode number changes? */ 89 inode = dentry->d_inode;
90 if (dentry->d_inode != NULL) 90 /* update inode in place if i_ino didn't change */
91 if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) {
92 cifs_fattr_to_inode(inode, fattr);
91 return dentry; 93 return dentry;
94 }
92 d_drop(dentry); 95 d_drop(dentry);
93 dput(dentry); 96 dput(dentry);
94 } 97 }
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 3097ee58fd7d..f25d4ea14be4 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -365,16 +365,14 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
365 if (mid == NULL) 365 if (mid == NULL)
366 return -ENOMEM; 366 return -ENOMEM;
367 367
368 /* put it on the pending_mid_q */
369 spin_lock(&GlobalMid_Lock);
370 list_add_tail(&mid->qhead, &server->pending_mid_q);
371 spin_unlock(&GlobalMid_Lock);
372
373 rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number); 368 rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
374 if (rc) 369 if (rc) {
375 delete_mid(mid); 370 DeleteMidQEntry(mid);
371 return rc;
372 }
373
376 *ret_mid = mid; 374 *ret_mid = mid;
377 return rc; 375 return 0;
378} 376}
379 377
380/* 378/*
@@ -407,17 +405,21 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
407 mid->callback_data = cbdata; 405 mid->callback_data = cbdata;
408 mid->mid_state = MID_REQUEST_SUBMITTED; 406 mid->mid_state = MID_REQUEST_SUBMITTED;
409 407
408 /* put it on the pending_mid_q */
409 spin_lock(&GlobalMid_Lock);
410 list_add_tail(&mid->qhead, &server->pending_mid_q);
411 spin_unlock(&GlobalMid_Lock);
412
413
410 cifs_in_send_inc(server); 414 cifs_in_send_inc(server);
411 rc = smb_sendv(server, iov, nvec); 415 rc = smb_sendv(server, iov, nvec);
412 cifs_in_send_dec(server); 416 cifs_in_send_dec(server);
413 cifs_save_when_sent(mid); 417 cifs_save_when_sent(mid);
414 mutex_unlock(&server->srv_mutex); 418 mutex_unlock(&server->srv_mutex);
415 419
416 if (rc) 420 if (rc == 0)
417 goto out_err; 421 return 0;
418 422
419 return rc;
420out_err:
421 delete_mid(mid); 423 delete_mid(mid);
422 add_credits(server, 1); 424 add_credits(server, 1);
423 wake_up(&server->request_q); 425 wake_up(&server->request_q);