summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/file.c30
-rw-r--r--fs/cifs/misc.c25
-rw-r--r--fs/cifs/smb2misc.c6
4 files changed, 53 insertions, 10 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 5b18d4585740..585ad3207cb1 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1333,6 +1333,7 @@ cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
1333} 1333}
1334 1334
1335struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file); 1335struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file);
1336void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_hdlr);
1336void cifsFileInfo_put(struct cifsFileInfo *cifs_file); 1337void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
1337 1338
1338#define CIFS_CACHE_READ_FLG 1 1339#define CIFS_CACHE_READ_FLG 1
@@ -1855,6 +1856,7 @@ GLOBAL_EXTERN spinlock_t gidsidlock;
1855#endif /* CONFIG_CIFS_ACL */ 1856#endif /* CONFIG_CIFS_ACL */
1856 1857
1857void cifs_oplock_break(struct work_struct *work); 1858void cifs_oplock_break(struct work_struct *work);
1859void cifs_queue_oplock_break(struct cifsFileInfo *cfile);
1858 1860
1859extern const struct slow_work_ops cifs_oplock_break_ops; 1861extern const struct slow_work_ops cifs_oplock_break_ops;
1860extern struct workqueue_struct *cifsiod_wq; 1862extern struct workqueue_struct *cifsiod_wq;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 89006e044973..9c0ccc06d172 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -360,13 +360,31 @@ cifsFileInfo_get(struct cifsFileInfo *cifs_file)
360 return cifs_file; 360 return cifs_file;
361} 361}
362 362
363/* 363/**
364 * Release a reference on the file private data. This may involve closing 364 * cifsFileInfo_put - release a reference of file priv data
365 * the filehandle out on the server. Must be called without holding 365 *
366 * tcon->open_file_lock and cifs_file->file_info_lock. 366 * Always potentially wait for oplock handler. See _cifsFileInfo_put().
367 */ 367 */
368void cifsFileInfo_put(struct cifsFileInfo *cifs_file) 368void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
369{ 369{
370 _cifsFileInfo_put(cifs_file, true);
371}
372
373/**
374 * _cifsFileInfo_put - release a reference of file priv data
375 *
376 * This may involve closing the filehandle @cifs_file out on the
377 * server. Must be called without holding tcon->open_file_lock and
378 * cifs_file->file_info_lock.
379 *
380 * If @wait_for_oplock_handler is true and we are releasing the last
381 * reference, wait for any running oplock break handler of the file
382 * and cancel any pending one. If calling this function from the
383 * oplock break handler, you need to pass false.
384 *
385 */
386void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
387{
370 struct inode *inode = d_inode(cifs_file->dentry); 388 struct inode *inode = d_inode(cifs_file->dentry);
371 struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); 389 struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
372 struct TCP_Server_Info *server = tcon->ses->server; 390 struct TCP_Server_Info *server = tcon->ses->server;
@@ -414,7 +432,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
414 432
415 spin_unlock(&tcon->open_file_lock); 433 spin_unlock(&tcon->open_file_lock);
416 434
417 oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break); 435 oplock_break_cancelled = wait_oplock_handler ?
436 cancel_work_sync(&cifs_file->oplock_break) : false;
418 437
419 if (!tcon->need_reconnect && !cifs_file->invalidHandle) { 438 if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
420 struct TCP_Server_Info *server = tcon->ses->server; 439 struct TCP_Server_Info *server = tcon->ses->server;
@@ -4603,6 +4622,7 @@ void cifs_oplock_break(struct work_struct *work)
4603 cinode); 4622 cinode);
4604 cifs_dbg(FYI, "Oplock release rc = %d\n", rc); 4623 cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
4605 } 4624 }
4625 _cifsFileInfo_put(cfile, false /* do not wait for ourself */);
4606 cifs_done_oplock_break(cinode); 4626 cifs_done_oplock_break(cinode);
4607} 4627}
4608 4628
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index bee203055b30..1e1626a2cfc3 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -501,8 +501,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
501 CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, 501 CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
502 &pCifsInode->flags); 502 &pCifsInode->flags);
503 503
504 queue_work(cifsoplockd_wq, 504 cifs_queue_oplock_break(netfile);
505 &netfile->oplock_break);
506 netfile->oplock_break_cancelled = false; 505 netfile->oplock_break_cancelled = false;
507 506
508 spin_unlock(&tcon->open_file_lock); 507 spin_unlock(&tcon->open_file_lock);
@@ -607,6 +606,28 @@ void cifs_put_writer(struct cifsInodeInfo *cinode)
607 spin_unlock(&cinode->writers_lock); 606 spin_unlock(&cinode->writers_lock);
608} 607}
609 608
609/**
610 * cifs_queue_oplock_break - queue the oplock break handler for cfile
611 *
612 * This function is called from the demultiplex thread when it
613 * receives an oplock break for @cfile.
614 *
615 * Assumes the tcon->open_file_lock is held.
616 * Assumes cfile->file_info_lock is NOT held.
617 */
618void cifs_queue_oplock_break(struct cifsFileInfo *cfile)
619{
620 /*
621 * Bump the handle refcount now while we hold the
622 * open_file_lock to enforce the validity of it for the oplock
623 * break handler. The matching put is done at the end of the
624 * handler.
625 */
626 cifsFileInfo_get(cfile);
627
628 queue_work(cifsoplockd_wq, &cfile->oplock_break);
629}
630
610void cifs_done_oplock_break(struct cifsInodeInfo *cinode) 631void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
611{ 632{
612 clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags); 633 clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags);
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 0e3570e40ff8..e311f58dc1c8 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -555,7 +555,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
555 clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, 555 clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
556 &cinode->flags); 556 &cinode->flags);
557 557
558 queue_work(cifsoplockd_wq, &cfile->oplock_break); 558 cifs_queue_oplock_break(cfile);
559 kfree(lw); 559 kfree(lw);
560 return true; 560 return true;
561 } 561 }
@@ -712,8 +712,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
712 CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, 712 CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
713 &cinode->flags); 713 &cinode->flags);
714 spin_unlock(&cfile->file_info_lock); 714 spin_unlock(&cfile->file_info_lock);
715 queue_work(cifsoplockd_wq, 715
716 &cfile->oplock_break); 716 cifs_queue_oplock_break(cfile);
717 717
718 spin_unlock(&tcon->open_file_lock); 718 spin_unlock(&tcon->open_file_lock);
719 spin_unlock(&cifs_tcp_ses_lock); 719 spin_unlock(&cifs_tcp_ses_lock);