diff options
Diffstat (limited to 'fs/cifs/misc.c')
| -rw-r--r-- | fs/cifs/misc.c | 74 | 
1 files changed, 72 insertions, 2 deletions
| diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 2f9f3790679d..3b0c62e622da 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -466,8 +466,22 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)  				cifs_dbg(FYI, "file id match, oplock break\n");  				pCifsInode = CIFS_I(netfile->dentry->d_inode); -				cifs_set_oplock_level(pCifsInode, -					pSMB->OplockLevel ? OPLOCK_READ : 0); +				set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, +					&pCifsInode->flags); + +				/* +				 * Set flag if the server downgrades the oplock +				 * to L2 else clear. +				 */ +				if (pSMB->OplockLevel) +					set_bit( +					   CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, +					   &pCifsInode->flags); +				else +					clear_bit( +					   CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, +					   &pCifsInode->flags); +  				queue_work(cifsiod_wq,  					   &netfile->oplock_break);  				netfile->oplock_break_cancelled = false; @@ -551,6 +565,62 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)  		cinode->oplock = 0;  } +static int +cifs_oplock_break_wait(void *unused) +{ +	schedule(); +	return signal_pending(current) ? -ERESTARTSYS : 0; +} + +/* + * We wait for oplock breaks to be processed before we attempt to perform + * writes. + */ +int cifs_get_writer(struct cifsInodeInfo *cinode) +{ +	int rc; + +start: +	rc = wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK, +				   cifs_oplock_break_wait, TASK_KILLABLE); +	if (rc) +		return rc; + +	spin_lock(&cinode->writers_lock); +	if (!cinode->writers) +		set_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags); +	cinode->writers++; +	/* Check to see if we have started servicing an oplock break */ +	if (test_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags)) { +		cinode->writers--; +		if (cinode->writers == 0) { +			clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags); +			wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS); +		} +		spin_unlock(&cinode->writers_lock); +		goto start; +	} +	spin_unlock(&cinode->writers_lock); +	return 0; +} + +void cifs_put_writer(struct cifsInodeInfo *cinode) +{ +	spin_lock(&cinode->writers_lock); +	cinode->writers--; +	if (cinode->writers == 0) { +		clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags); +		wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS); +	} +	spin_unlock(&cinode->writers_lock); +} + +void cifs_done_oplock_break(struct cifsInodeInfo *cinode) +{ +	clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags); +	wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK); +} +  bool  backup_cred(struct cifs_sb_info *cifs_sb)  { | 

