CHROMIUM: Fix mismatched mutex_unlock in swapon()

This change fixes the lockdep splat (when CONFIG_LOCKDEP=y and
CONFIG_DEBUG_MUTEXES=y) that happens when "swapon file" is ran:

 ------------[ cut here ]------------
 WARNING: CPU: 1 PID: 676 at kernel/locking/lockdep.c:3382 lock_release+0x2a1/0x630()
 DEBUG_LOCKS_WARN_ON(depth <= 0)
 CPU: 1 PID: 676 Comm: swapon Not tainted 4.4.70-xfstests-09717-g45af45ae8cb0 #1
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
  0000000000000000 ffff88007ac2bce8 ffffffff814b384c ffff88007ac2bd30
  ffffffff819b4eb0 ffff88007ac2bd20 ffffffff81077571 ffff88007b24e760
  ffffffff81187ad3 ffff88007ac2be28 ffffffff81d2a5d8 ffff88007b7b87c0
 Call Trace:
  [<ffffffff814b384c>] dump_stack+0x85/0xc9
  [<ffffffff81077571>] warn_slowpath_common+0x81/0xc0
  [<ffffffff81187ad3>] ? SyS_swapon+0xc73/0xf30
  [<ffffffff8107762c>] warn_slowpath_fmt+0x4c/0x50
  [<ffffffff810415b5>] ? kvm_clock_read+0x25/0x30
  [<ffffffff810c9bf1>] lock_release+0x2a1/0x630
  [<ffffffff810a9fe1>] ? sched_clock_cpu+0x91/0xb0
  [<ffffffff81187164>] ? SyS_swapon+0x304/0xf30
  [<ffffffff816f8073>] __mutex_unlock_slowpath+0x43/0x3c0
  [<ffffffff816f8402>] mutex_unlock+0x12/0x20
  [<ffffffff81187ad3>] SyS_swapon+0xc73/0xf30
  [<ffffffff816ff207>] ? int_ret_from_sys_call+0x52/0x9f
  [<ffffffff81001017>] ? trace_hardirqs_on_thunk+0x17/0x19
  [<ffffffff816ff072>] entry_SYSCALL_64_fastpath+0x12/0x76
 ---[ end trace 04cc26a572ac8e68 ]---

In upstream kernel, claim_swapfile() does and unconditional
mutex_lock(&inode->i_mutex) when inode is a regular file. This mutex is
then unlocked in swapon() function's return path. On ChromiumOS though,
since the mutex_lock() is compiled out or disabled by sysctl, the
corresponding mutex_unlock() generates the splat.
The presence of sysctl_disk_based_swap makes it tricky because the
sysctl value may change (in theory) between claim_swapfile() and
the swapon() exit path.
To fix this, instead of compiling out the upstream code, we add a check
for the sysctl value (which is 0 by default) at the beginning of the
swapon() function  and do a proper mutex lock/unlock in all cases.

BUG=b:62107328
TEST=Following steps reproduced the issue:
  $ dd if=/dev/zero of=/swapfile count=1000 bs=4096
  $ mkswap -U <uuid> /swapfile
  $ swapon /swapfile
After the patch, there is no warning.

Change-Id: I81aac1c07bfbad142b699b05a4136251e78b2f71
Reviewed-on: https://chromium-review.googlesource.com/535083
Commit-Ready: Aditya Kali <adityakali@google.com>
Tested-by: Aditya Kali <adityakali@google.com>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 38a863b..23ce2c4 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2195,11 +2195,11 @@
 	return p;
 }
 
-#ifdef CONFIG_DISK_BASED_SWAP
+/* This sysctl is only exposed when CONFIG_DISK_BASED_SWAP is enabled. */
 int sysctl_disk_based_swap;
-#endif
 
-static int claim_swapfile(struct swap_info_struct *p, struct inode *inode)
+static int claim_swapfile(struct swap_info_struct *p, struct inode *inode,
+			  bool allow_disk_based_swap)
 {
 	int error;
 	/* On Chromium OS, we only support zram swap devices. */
@@ -2223,13 +2223,11 @@
 		if (error < 0)
 			return error;
 		p->flags |= SWP_BLKDEV;
-#ifdef CONFIG_DISK_BASED_SWAP
-	} else if (sysctl_disk_based_swap && S_ISREG(inode->i_mode)) {
+	} else if (S_ISREG(inode->i_mode) && allow_disk_based_swap) {
 		p->bdev = inode->i_sb->s_bdev;
 		mutex_lock(&inode->i_mutex);
 		if (IS_SWAPFILE(inode))
 			return -EBUSY;
-#endif
 	} else
 		return -EINVAL;
 
@@ -2432,6 +2430,7 @@
 	unsigned long *frontswap_map = NULL;
 	struct page *page = NULL;
 	struct inode *inode = NULL;
+	bool allow_disk_based_swap = sysctl_disk_based_swap ? true : false;
 
 	if (swap_flags & ~SWAP_FLAGS_VALID)
 		return -EINVAL;
@@ -2463,7 +2462,7 @@
 	inode = mapping->host;
 
 	/* If S_ISREG(inode->i_mode) will do mutex_lock(&inode->i_mutex); */
-	error = claim_swapfile(p, inode);
+	error = claim_swapfile(p, inode, allow_disk_based_swap);
 	if (unlikely(error))
 		goto bad_swap;
 
@@ -2607,7 +2606,8 @@
 	vfree(cluster_info);
 	if (swap_file) {
 		if (inode && S_ISREG(inode->i_mode)) {
-			mutex_unlock(&inode->i_mutex);
+			if (allow_disk_based_swap)
+				mutex_unlock(&inode->i_mutex);
 			inode = NULL;
 		}
 		filp_close(swap_file, NULL);