diff options
Diffstat (limited to 'fs/cifs/smb2misc.c')
| -rw-r--r-- | fs/cifs/smb2misc.c | 73 | 
1 files changed, 52 insertions, 21 deletions
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 157992864ce7..d88e2683626e 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -508,15 +508,31 @@ cifs_ses_oplock_break(struct work_struct *work)  	kfree(lw);  } +static void +smb2_queue_pending_open_break(struct tcon_link *tlink, __u8 *lease_key, +			      __le32 new_lease_state) +{ +	struct smb2_lease_break_work *lw; + +	lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL); +	if (!lw) { +		cifs_put_tlink(tlink); +		return; +	} + +	INIT_WORK(&lw->lease_break, cifs_ses_oplock_break); +	lw->tlink = tlink; +	lw->lease_state = new_lease_state; +	memcpy(lw->lease_key, lease_key, SMB2_LEASE_KEY_SIZE); +	queue_work(cifsiod_wq, &lw->lease_break); +} +  static bool -smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, -		    struct smb2_lease_break_work *lw) +smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)  { -	bool found;  	__u8 lease_state;  	struct list_head *tmp;  	struct cifsFileInfo *cfile; -	struct cifs_pending_open *open;  	struct cifsInodeInfo *cinode;  	int ack_req = le32_to_cpu(rsp->Flags &  				  SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); @@ -546,22 +562,29 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,  		cfile->oplock_level = lease_state;  		cifs_queue_oplock_break(cfile); -		kfree(lw);  		return true;  	} -	found = false; +	return false; +} + +static struct cifs_pending_open * +smb2_tcon_find_pending_open_lease(struct cifs_tcon *tcon, +				  struct smb2_lease_break *rsp) +{ +	__u8 lease_state = le32_to_cpu(rsp->NewLeaseState); +	int ack_req = le32_to_cpu(rsp->Flags & +				  SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); +	struct cifs_pending_open *open; +	struct cifs_pending_open *found = NULL; +  	list_for_each_entry(open, &tcon->pending_opens, olist) {  		if (memcmp(open->lease_key, rsp->LeaseKey,  			   SMB2_LEASE_KEY_SIZE))  			continue;  		if (!found && ack_req) { -			found = true; -			memcpy(lw->lease_key, open->lease_key, -			       SMB2_LEASE_KEY_SIZE); -			lw->tlink = cifs_get_tlink(open->tlink); -			queue_work(cifsiod_wq, &lw->lease_break); +			found = open;  		}  		cifs_dbg(FYI, "found in the pending open list\n"); @@ -582,14 +605,7 @@ smb2_is_valid_lease_break(char *buffer)  	struct TCP_Server_Info *server;  	struct cifs_ses *ses;  	struct cifs_tcon *tcon; -	struct smb2_lease_break_work *lw; - -	lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL); -	if (!lw) -		return false; - -	INIT_WORK(&lw->lease_break, cifs_ses_oplock_break); -	lw->lease_state = rsp->NewLeaseState; +	struct cifs_pending_open *open;  	cifs_dbg(FYI, "Checking for lease break\n"); @@ -607,11 +623,27 @@ smb2_is_valid_lease_break(char *buffer)  				spin_lock(&tcon->open_file_lock);  				cifs_stats_inc(  				    &tcon->stats.cifs_stats.num_oplock_brks); -				if (smb2_tcon_has_lease(tcon, rsp, lw)) { +				if (smb2_tcon_has_lease(tcon, rsp)) {  					spin_unlock(&tcon->open_file_lock);  					spin_unlock(&cifs_tcp_ses_lock);  					return true;  				} +				open = smb2_tcon_find_pending_open_lease(tcon, +									 rsp); +				if (open) { +					__u8 lease_key[SMB2_LEASE_KEY_SIZE]; +					struct tcon_link *tlink; + +					tlink = cifs_get_tlink(open->tlink); +					memcpy(lease_key, open->lease_key, +					       SMB2_LEASE_KEY_SIZE); +					spin_unlock(&tcon->open_file_lock); +					spin_unlock(&cifs_tcp_ses_lock); +					smb2_queue_pending_open_break(tlink, +								      lease_key, +								      rsp->NewLeaseState); +					return true; +				}  				spin_unlock(&tcon->open_file_lock);  				if (tcon->crfid.is_valid && @@ -629,7 +661,6 @@ smb2_is_valid_lease_break(char *buffer)  		}  	}  	spin_unlock(&cifs_tcp_ses_lock); -	kfree(lw);  	cifs_dbg(FYI, "Can not process lease break - no lease matched\n");  	return false;  }  |