diff options
Diffstat (limited to 'fs/cifs/misc.c')
| -rw-r--r-- | fs/cifs/misc.c | 49 | 
1 files changed, 45 insertions, 4 deletions
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index bee203055b30..b1a696a73f7c 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)  					   CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,  					   &pCifsInode->flags); -				queue_work(cifsoplockd_wq, -					   &netfile->oplock_break); +				cifs_queue_oplock_break(netfile);  				netfile->oplock_break_cancelled = false;  				spin_unlock(&tcon->open_file_lock); @@ -607,6 +606,28 @@ void cifs_put_writer(struct cifsInodeInfo *cinode)  	spin_unlock(&cinode->writers_lock);  } +/** + * cifs_queue_oplock_break - queue the oplock break handler for cfile + * + * This function is called from the demultiplex thread when it + * receives an oplock break for @cfile. + * + * Assumes the tcon->open_file_lock is held. + * Assumes cfile->file_info_lock is NOT held. + */ +void cifs_queue_oplock_break(struct cifsFileInfo *cfile) +{ +	/* +	 * Bump the handle refcount now while we hold the +	 * open_file_lock to enforce the validity of it for the oplock +	 * break handler. The matching put is done at the end of the +	 * handler. +	 */ +	cifsFileInfo_get(cfile); + +	queue_work(cifsoplockd_wq, &cfile->oplock_break); +} +  void cifs_done_oplock_break(struct cifsInodeInfo *cinode)  {  	clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags); @@ -768,6 +789,11 @@ cifs_aio_ctx_alloc(void)  {  	struct cifs_aio_ctx *ctx; +	/* +	 * Must use kzalloc to initialize ctx->bv to NULL and ctx->direct_io +	 * to false so that we know when we have to unreference pages within +	 * cifs_aio_ctx_release() +	 */  	ctx = kzalloc(sizeof(struct cifs_aio_ctx), GFP_KERNEL);  	if (!ctx)  		return NULL; @@ -786,7 +812,23 @@ cifs_aio_ctx_release(struct kref *refcount)  					struct cifs_aio_ctx, refcount);  	cifsFileInfo_put(ctx->cfile); -	kvfree(ctx->bv); + +	/* +	 * ctx->bv is only set if setup_aio_ctx_iter() was call successfuly +	 * which means that iov_iter_get_pages() was a success and thus that +	 * we have taken reference on pages. +	 */ +	if (ctx->bv) { +		unsigned i; + +		for (i = 0; i < ctx->npages; i++) { +			if (ctx->should_dirty) +				set_page_dirty(ctx->bv[i].bv_page); +			put_page(ctx->bv[i].bv_page); +		} +		kvfree(ctx->bv); +	} +  	kfree(ctx);  } @@ -917,7 +959,6 @@ cifs_alloc_hash(const char *name,  	}  	(*sdesc)->shash.tfm = *shash; -	(*sdesc)->shash.flags = 0x0;  	return 0;  }  | 
