[1/2] cifs: Handle unsupported file locks gracefully

Message ID 20180629205500.7950-1-paulo@paulo.ac
State New
Headers show
Series
  • [1/2] cifs: Handle unsupported file locks gracefully
Related show

Commit Message

Paulo Alcantara June 29, 2018, 8:54 p.m.
In case we don't support a specific file lock (that being determined by
looking at fl_flags or fl_type), return an appropriate error back to
userspace.

Also, do some cleanup in cifs_lock() and its friends.

Signed-off-by: Paulo Alcantara <palcantara@suse.de>
---
 fs/cifs/file.c | 105 ++++++++++++++++++++++++-------------------------
 1 file changed, 51 insertions(+), 54 deletions(-)

Patch

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 8d41ca7bfcf1..259167f32580 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1303,51 +1303,55 @@  cifs_push_locks(struct cifsFileInfo *cfile)
 	return rc;
 }
 
-static void
-cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock,
-		bool *wait_flag, struct TCP_Server_Info *server)
+static int cifs_read_flock(struct file_lock *flock, __u32 *type, bool *lock,
+			   bool *wait_flag, struct TCP_Server_Info *server)
 {
+	unsigned int flags = FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS |
+		FL_LEASE | FL_CLOSE;
+
+	if (flock->fl_flags & ~flags) {
+		cifs_dbg(FYI, "Unknown lock flags 0x%x\n", flock->fl_flags);
+		return -EOPNOTSUPP;
+	}
+
+#ifdef CONFIG_CIFS_DEBUG2
 	if (flock->fl_flags & FL_POSIX)
 		cifs_dbg(FYI, "Posix\n");
 	if (flock->fl_flags & FL_FLOCK)
 		cifs_dbg(FYI, "Flock\n");
-	if (flock->fl_flags & FL_SLEEP) {
-		cifs_dbg(FYI, "Blocking lock\n");
-		*wait_flag = true;
-	}
 	if (flock->fl_flags & FL_ACCESS)
 		cifs_dbg(FYI, "Process suspended by mandatory locking - not implemented yet\n");
 	if (flock->fl_flags & FL_LEASE)
 		cifs_dbg(FYI, "Lease on file - not implemented yet\n");
-	if (flock->fl_flags &
-	    (~(FL_POSIX | FL_FLOCK | FL_SLEEP |
-	       FL_ACCESS | FL_LEASE | FL_CLOSE)))
-		cifs_dbg(FYI, "Unknown lock flags 0x%x\n", flock->fl_flags);
+#endif
+	if (flock->fl_flags & FL_SLEEP) {
+		cifs_dbg(FYI, "Blocking lock\n");
+		*wait_flag = true;
+	}
+
+	cifs_dbg(FYI, "Lock type: 0x%02x\n", flock->fl_type);
 
 	*type = server->vals->large_lock_type;
-	if (flock->fl_type == F_WRLCK) {
-		cifs_dbg(FYI, "F_WRLCK\n");
-		*type |= server->vals->exclusive_lock_type;
-		*lock = 1;
-	} else if (flock->fl_type == F_UNLCK) {
-		cifs_dbg(FYI, "F_UNLCK\n");
-		*type |= server->vals->unlock_lock_type;
-		*unlock = 1;
-		/* Check if unlock includes more than one lock range */
-	} else if (flock->fl_type == F_RDLCK) {
-		cifs_dbg(FYI, "F_RDLCK\n");
+
+	switch (flock->fl_type) {
+	case F_RDLCK:
+	case F_SHLCK:
 		*type |= server->vals->shared_lock_type;
-		*lock = 1;
-	} else if (flock->fl_type == F_EXLCK) {
-		cifs_dbg(FYI, "F_EXLCK\n");
+		break;
+	case F_WRLCK:
+	case F_EXLCK:
 		*type |= server->vals->exclusive_lock_type;
-		*lock = 1;
-	} else if (flock->fl_type == F_SHLCK) {
-		cifs_dbg(FYI, "F_SHLCK\n");
-		*type |= server->vals->shared_lock_type;
-		*lock = 1;
-	} else
-		cifs_dbg(FYI, "Unknown type of lock\n");
+		break;
+	case F_UNLCK:
+		*type |= server->vals->unlock_lock_type;
+		break;
+	default:
+		cifs_dbg(FYI, "Unknown lock type\n");
+		return -EINVAL;
+	}
+
+	*lock = !(*type & server->vals->unlock_lock_type);
+	return 0;
 }
 
 static int
@@ -1547,10 +1551,9 @@  cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
 	return rc;
 }
 
-static int
-cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
-	   bool wait_flag, bool posix_lck, int lock, int unlock,
-	   unsigned int xid)
+static int cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
+		      bool wait_flag, bool posix_lck, bool lock,
+		      unsigned int xid)
 {
 	int rc = 0;
 	__u64 length = 1 + flock->fl_end - flock->fl_start;
@@ -1571,7 +1574,7 @@  cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
 		else
 			posix_lock_type = CIFS_WRLCK;
 
-		if (unlock == 1)
+		if (!lock)
 			posix_lock_type = CIFS_UNLCK;
 
 		rc = CIFSSMBPosixLock(xid, tcon, cfile->fid.netfid,
@@ -1619,8 +1622,9 @@  cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
 		}
 
 		cifs_lock_add(cfile, lock);
-	} else if (unlock)
+	} else {
 		rc = server->ops->mand_unlock_range(cfile, flock, xid);
+	}
 
 out:
 	if (flock->fl_flags & FL_POSIX && !rc)
@@ -1631,7 +1635,7 @@  cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
 int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 {
 	int rc, xid;
-	int lock = 0, unlock = 0;
+	bool lock = false;
 	bool wait_flag = false;
 	bool posix_lck = false;
 	struct cifs_sb_info *cifs_sb;
@@ -1651,8 +1655,10 @@  int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 	cfile = (struct cifsFileInfo *)file->private_data;
 	tcon = tlink_tcon(cfile->tlink);
 
-	cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag,
-			tcon->ses->server);
+	rc = cifs_read_flock(flock, &type, &lock, &wait_flag,
+			     tcon->ses->server);
+	if (rc)
+		goto out;
 
 	cifs_sb = CIFS_FILE_SB(file);
 	netfid = cfile->fid.netfid;
@@ -1668,21 +1674,12 @@  int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
 	 */
 	if (IS_GETLK(cmd)) {
 		rc = cifs_getlk(file, flock, type, wait_flag, posix_lck, xid);
-		free_xid(xid);
-		return rc;
-	}
-
-	if (!lock && !unlock) {
-		/*
-		 * if no lock or unlock then nothing to do since we do not
-		 * know what it is
-		 */
-		free_xid(xid);
-		return -EOPNOTSUPP;
+	} else {
+		rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock,
+				xid);
 	}
 
-	rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock, unlock,
-			xid);
+out:
 	free_xid(xid);
 	return rc;
 }