Re: [PATCH v3] cifs: Fix leak when handling lease break for cached root fid

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2020-07-06 10:30:27 +0200, Aurélien Aptel wrote:
Paul Aurich <paul@xxxxxxxxxxxxxx> writes:
Changes since v2:
   - address sparse lock warnings by inlining smb2_tcon_has_lease and
     hardcoding some return values (seems to help sparse's analysis)

Ah, I think the issue is not the inlining but rather you need to
instruct sparse that smb2_tcon_hash_lease is expected to release the
lock.

https://www.kernel.org/doc/html/v4.12/dev-tools/sparse.html#using-sparse-for-lock-checking

Probably with __releases somewhere in the func prototype.

I tried various iterations of that without finding one that seems to work. I suspect it's because the unlocking is _conditional_.

w/o the inline and with __releases(&cifs_tcp_ses_lock):

fs/cifs/smb2misc.c:508:1: warning: context imbalance in 'smb2_tcon_has_lease' - different lock contexts for basic block fs/cifs/smb2misc.c:612:25: warning: context imbalance in 'smb2_is_valid_lease_break'- different lock contexts for basic block


Digging further, I found __acquire and __release (not plural), which can be used in individual blocks. The following seems to silence the sparse warnings - does this seem valid?

@@ -504,7 +504,7 @@ cifs_ses_oplock_break(struct work_struct *work)
 	kfree(lw);
 }
-static inline bool
+static bool
 smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
 {
 	bool found;
@@ -521,6 +521,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
lease_state = le32_to_cpu(rsp->NewLeaseState); + __acquire(cifs_tcp_ses_lock);
 	spin_lock(&tcon->open_file_lock);
 	list_for_each(tmp, &tcon->openFileList) {
 		cfile = list_entry(tmp, struct cifsFileInfo, tlist);
@@ -571,8 +572,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
 	}
spin_unlock(&tcon->open_file_lock);
-	if (!found)
-		return false;
+	if (found) {
 		spin_unlock(&cifs_tcp_ses_lock);
lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
@@ -586,7 +586,12 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp)
 		lw->lease_state = rsp->NewLeaseState;
 		memcpy(lw->lease_key, lease_key, SMB2_LEASE_KEY_SIZE);
 		queue_work(cifsiod_wq, &lw->lease_break);
-	return true;
+	} else {
+		/* for sparse */
+		__release(&cifs_tcp_ses_lock);
+	}
+
+	return found;
 }
static bool
@@ -614,6 +619,8 @@ smb2_is_valid_lease_break(char *buffer)
 				cifs_stats_inc(
 				    &tcon->stats.cifs_stats.num_oplock_brks);
 				if (smb2_tcon_has_lease(tcon, rsp)) {
+					/* Unlocked in smb2_tcon_has_lease */
+					__release(&cifs_tcp_ses_lock);
 					return true;
 				}


~Paul




[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux