From: Jeff Layton Date: Tue, 26 Jul 2011 16:20:17 +0000 (-0400) Subject: cifs: simplify refcounting for oplock breaks X-Git-Tag: v3.1-rc1~96^2~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ad635942c869ad8fc9af270d4998c42b4e978b32;p=platform%2Fkernel%2Flinux-3.10.git cifs: simplify refcounting for oplock breaks Currently, we take a sb->s_active reference and a cifsFileInfo reference when an oplock break workqueue job is queued. This is unnecessary and more complicated than it needs to be. Also as Al points out, deactivate_super has non-trivial locking implications so it's best to avoid that if we can. Instead, just cancel any pending oplock breaks for this filehandle synchronously in cifsFileInfo_put after taking it off the lists. That should ensure that this job doesn't outlive the structures it depends on. Reported-by: Al Viro Signed-off-by: Jeff Layton Signed-off-by: Steve French --- diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8655174..212e562 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -86,24 +86,6 @@ extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; -void -cifs_sb_active(struct super_block *sb) -{ - struct cifs_sb_info *server = CIFS_SB(sb); - - if (atomic_inc_return(&server->active) == 1) - atomic_inc(&sb->s_active); -} - -void -cifs_sb_deactive(struct super_block *sb) -{ - struct cifs_sb_info *server = CIFS_SB(sb); - - if (atomic_dec_and_test(&server->active)) - deactivate_super(sb); -} - static int cifs_read_super(struct super_block *sb) { diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index fbd050c..cb71dc1 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -41,10 +41,6 @@ extern struct file_system_type cifs_fs_type; extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops_smallbuf; -/* Functions related to super block operations */ -extern void cifs_sb_active(struct super_block *sb); -extern void cifs_sb_deactive(struct super_block *sb); - /* Functions related to inodes */ extern const struct inode_operations cifs_dir_inode_ops; extern struct inode *cifs_root_iget(struct super_block *); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1fcf4e5..38ce6d4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -942,8 +942,6 @@ GLOBAL_EXTERN spinlock_t siduidlock; GLOBAL_EXTERN spinlock_t sidgidlock; void cifs_oplock_break(struct work_struct *work); -void cifs_oplock_break_get(struct cifsFileInfo *cfile); -void cifs_oplock_break_put(struct cifsFileInfo *cfile); extern const struct slow_work_ops cifs_oplock_break_ops; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 378acdaf..9f41a10 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -314,6 +314,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) } spin_unlock(&cifs_file_list_lock); + cancel_work_sync(&cifs_file->oplock_break); + if (!tcon->need_reconnect && !cifs_file->invalidHandle) { int xid, rc; @@ -2418,31 +2420,6 @@ void cifs_oplock_break(struct work_struct *work) cinode->clientCanCacheRead ? 1 : 0); cFYI(1, "Oplock release rc = %d", rc); } - - /* - * We might have kicked in before is_valid_oplock_break() - * finished grabbing reference for us. Make sure it's done by - * waiting for cifs_file_list_lock. - */ - spin_lock(&cifs_file_list_lock); - spin_unlock(&cifs_file_list_lock); - - cifs_oplock_break_put(cfile); -} - -/* must be called while holding cifs_file_list_lock */ -void cifs_oplock_break_get(struct cifsFileInfo *cfile) -{ - cifs_sb_active(cfile->dentry->d_sb); - cifsFileInfo_get(cfile); -} - -void cifs_oplock_break_put(struct cifsFileInfo *cfile) -{ - struct super_block *sb = cfile->dentry->d_sb; - - cifsFileInfo_put(cfile); - cifs_sb_deactive(sb); } const struct address_space_operations cifs_addr_ops = { diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 03a1f491..7c16933 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -585,15 +585,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) cifs_set_oplock_level(pCifsInode, pSMB->OplockLevel ? OPLOCK_READ : 0); - /* - * cifs_oplock_break_put() can't be called - * from here. Get reference after queueing - * succeeded. cifs_oplock_break() will - * synchronize using cifs_file_list_lock. - */ - if (queue_work(system_nrt_wq, - &netfile->oplock_break)) - cifs_oplock_break_get(netfile); + queue_work(system_nrt_wq, + &netfile->oplock_break); netfile->oplock_break_cancelled = false; spin_unlock(&cifs_file_list_lock);