diff options
author | Pavel Shilovsky <pshilovsky@etersoft.ru> | 2012-09-19 09:22:45 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-09-24 22:46:33 -0400 |
commit | 233839b1df65a24c8b67b748fe7b18d86d0ad6d7 (patch) | |
tree | ba9af2849063c2213fc0fbecb494967f1e662806 /fs/cifs/file.c | |
parent | 0822f51426b51bd599b3a7e972b14aacaa045a92 (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.c | 35 |
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 | ||
370 | int cifs_open(struct inode *inode, struct file *file) | 387 | int 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 | } |