aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@etersoft.ru>2012-09-19 09:22:45 -0400
committerSteve French <smfrench@gmail.com>2012-09-24 22:46:33 -0400
commit233839b1df65a24c8b67b748fe7b18d86d0ad6d7 (patch)
treeba9af2849063c2213fc0fbecb494967f1e662806 /fs/cifs/file.c
parent0822f51426b51bd599b3a7e972b14aacaa045a92 (diff)
CIFS: Fix fast lease break after open problem
Now we walk though cifsFileInfo's list for every incoming lease break and look for an equivalent there. That approach misses lease breaks that come just after an open response - we don't have time to populate new cifsFileInfo structure to the list. Fix this by adding new list of pending opens and look for a lease there if we didn't find it in the list of cifsFileInfo structures. Signed-off-by: Pavel Shilovsky <pshilovsky@etersoft.ru> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r--fs/cifs/file.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e93e3d2c69e6..88e9c74e2cac 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -247,6 +247,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
247 struct cifsInodeInfo *cinode = CIFS_I(inode); 247 struct cifsInodeInfo *cinode = CIFS_I(inode);
248 struct cifsFileInfo *cfile; 248 struct cifsFileInfo *cfile;
249 struct cifs_fid_locks *fdlocks; 249 struct cifs_fid_locks *fdlocks;
250 struct cifs_tcon *tcon = tlink_tcon(tlink);
250 251
251 cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); 252 cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
252 if (cfile == NULL) 253 if (cfile == NULL)
@@ -274,10 +275,15 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
274 cfile->tlink = cifs_get_tlink(tlink); 275 cfile->tlink = cifs_get_tlink(tlink);
275 INIT_WORK(&cfile->oplock_break, cifs_oplock_break); 276 INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
276 mutex_init(&cfile->fh_mutex); 277 mutex_init(&cfile->fh_mutex);
277 tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
278 278
279 spin_lock(&cifs_file_list_lock); 279 spin_lock(&cifs_file_list_lock);
280 list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList)); 280 if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE)
281 oplock = fid->pending_open->oplock;
282 list_del(&fid->pending_open->olist);
283
284 tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
285
286 list_add(&cfile->tlist, &tcon->openFileList);
281 /* if readable file instance put first in list*/ 287 /* if readable file instance put first in list*/
282 if (file->f_mode & FMODE_READ) 288 if (file->f_mode & FMODE_READ)
283 list_add(&cfile->flist, &cinode->openFileList); 289 list_add(&cfile->flist, &cinode->openFileList);
@@ -307,9 +313,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
307{ 313{
308 struct inode *inode = cifs_file->dentry->d_inode; 314 struct inode *inode = cifs_file->dentry->d_inode;
309 struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); 315 struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
316 struct TCP_Server_Info *server = tcon->ses->server;
310 struct cifsInodeInfo *cifsi = CIFS_I(inode); 317 struct cifsInodeInfo *cifsi = CIFS_I(inode);
311 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 318 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
312 struct cifsLockInfo *li, *tmp; 319 struct cifsLockInfo *li, *tmp;
320 struct cifs_fid fid;
321 struct cifs_pending_open open;
313 322
314 spin_lock(&cifs_file_list_lock); 323 spin_lock(&cifs_file_list_lock);
315 if (--cifs_file->count > 0) { 324 if (--cifs_file->count > 0) {
@@ -317,6 +326,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
317 return; 326 return;
318 } 327 }
319 328
329 if (server->ops->get_lease_key)
330 server->ops->get_lease_key(inode, &fid);
331
332 /* store open in pending opens to make sure we don't miss lease break */
333 cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);
334
320 /* remove it from the lists */ 335 /* remove it from the lists */
321 list_del(&cifs_file->flist); 336 list_del(&cifs_file->flist);
322 list_del(&cifs_file->tlist); 337 list_del(&cifs_file->tlist);
@@ -348,6 +363,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
348 free_xid(xid); 363 free_xid(xid);
349 } 364 }
350 365
366 cifs_del_pending_open(&open);
367
351 /* 368 /*
352 * Delete any outstanding lock records. We'll lose them when the file 369 * Delete any outstanding lock records. We'll lose them when the file
353 * is closed anyway. 370 * is closed anyway.
@@ -368,6 +385,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
368} 385}
369 386
370int cifs_open(struct inode *inode, struct file *file) 387int cifs_open(struct inode *inode, struct file *file)
388
371{ 389{
372 int rc = -EACCES; 390 int rc = -EACCES;
373 unsigned int xid; 391 unsigned int xid;
@@ -380,6 +398,7 @@ int cifs_open(struct inode *inode, struct file *file)
380 char *full_path = NULL; 398 char *full_path = NULL;
381 bool posix_open_ok = false; 399 bool posix_open_ok = false;
382 struct cifs_fid fid; 400 struct cifs_fid fid;
401 struct cifs_pending_open open;
383 402
384 xid = get_xid(); 403 xid = get_xid();
385 404
@@ -401,7 +420,7 @@ int cifs_open(struct inode *inode, struct file *file)
401 cFYI(1, "inode = 0x%p file flags are 0x%x for %s", 420 cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
402 inode, file->f_flags, full_path); 421 inode, file->f_flags, full_path);
403 422
404 if (tcon->ses->server->oplocks) 423 if (server->oplocks)
405 oplock = REQ_OPLOCK; 424 oplock = REQ_OPLOCK;
406 else 425 else
407 oplock = 0; 426 oplock = 0;
@@ -434,20 +453,28 @@ int cifs_open(struct inode *inode, struct file *file)
434 */ 453 */
435 } 454 }
436 455
456 if (server->ops->get_lease_key)
457 server->ops->get_lease_key(inode, &fid);
458
459 cifs_add_pending_open(&fid, tlink, &open);
460
437 if (!posix_open_ok) { 461 if (!posix_open_ok) {
438 if (server->ops->get_lease_key) 462 if (server->ops->get_lease_key)
439 server->ops->get_lease_key(inode, &fid); 463 server->ops->get_lease_key(inode, &fid);
440 464
441 rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, 465 rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
442 file->f_flags, &oplock, &fid, xid); 466 file->f_flags, &oplock, &fid, xid);
443 if (rc) 467 if (rc) {
468 cifs_del_pending_open(&open);
444 goto out; 469 goto out;
470 }
445 } 471 }
446 472
447 cfile = cifs_new_fileinfo(&fid, file, tlink, oplock); 473 cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
448 if (cfile == NULL) { 474 if (cfile == NULL) {
449 if (server->ops->close) 475 if (server->ops->close)
450 server->ops->close(xid, tcon, &fid); 476 server->ops->close(xid, tcon, &fid);
477 cifs_del_pending_open(&open);
451 rc = -ENOMEM; 478 rc = -ENOMEM;
452 goto out; 479 goto out;
453 } 480 }