[PATCH V2] loopdev: report lost loop device file error

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

 



If a /dev/loopX is lost because someone might have removed it by mistake,
future losetup operations on that loop device will fail.
For examples, following cmds will fail when loop device file is lost.
- "losetup -d $loop_device"
- "losetup -f $file" or "mount $file $dev"

Since /sysfs still have the loop device intact, detect that and report
detailed log message to guide user to recover the lost loop device file.

    # ./losetup -a
    /dev/loop0: [64512]:19133870 (/tmp/test.img)
    # rm -rf /dev/loop0
    # ./losetup -d /dev/loop0
    /dev/loop0 is lost, run "mknod /dev/loop0 b 7 0" to recover it.
    lt-losetup: /dev/loop0: detach failed: No such file or directory

Signed-off-by: Junxiao Bi <junxiao.bi@xxxxxxxxxx>
---
v2 <- v1:
 - Reporting lost loop device file instead of using mknode to recreate
v1:
https://www.spinics.net/lists/util-linux-ng/msg17471.html

 lib/loopdev.c       | 37 ++++++++++++++++++++++++++++++-------
 sys-utils/losetup.c | 14 +++++---------
 2 files changed, 35 insertions(+), 16 deletions(-)

diff --git a/lib/loopdev.c b/lib/loopdev.c
index dae499f256fa..c8407857972a 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -279,6 +279,29 @@ static struct path_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc)
 	return lc->sysfs;
 }
 
+/*
+ * losetup cmds could fail if /dev/loopX is removed by mistake.
+ * This function will detect that and report a detailed error
+ * log to help sysadmin recreate the lost loop device file.
+ */
+static void loopcxt_scan_lost_device_file(struct loopdev_cxt *lc)
+{
+	static int scanned = 0;
+	dev_t devno;
+
+	/*only scan sysfs once for losetup cmd*/
+	if (!scanned)
+		scanned = 1;
+	else
+		return;
+	devno = sysfs_devname_to_devno(lc->device);
+	if (devno <= 0)
+		return;
+
+	fprintf(stderr, "%s is lost, run \"mknod %s b %d %d\" to recover it.\n",
+			lc->device, lc->device, major(devno), minor(devno));
+}
+
 static int __loopcxt_get_fd(struct loopdev_cxt *lc, mode_t mode)
 {
 	int old = -1;
@@ -304,6 +327,13 @@ static int __loopcxt_get_fd(struct loopdev_cxt *lc, mode_t mode)
 				mode == O_RDONLY ? "ro" :
 			        mode == O_RDWR ? "rw" : "??"));
 
+		/* loop device file not exist. */
+		if (lc->fd < 0 && errno == ENOENT) {
+			DBG(CXT, ul_debugobj(lc, "%s doesn't exist.",
+						lc->device));
+			loopcxt_scan_lost_device_file(lc);
+			errno = ENOENT;
+		}
 		if (lc->fd < 0 && old >= 0) {
 			/* restore original on error */
 			lc->fd = old;
@@ -416,13 +446,6 @@ static int loopiter_set_device(struct loopdev_cxt *lc, const char *device)
 	    !(lc->iter.flags & LOOPITER_FL_FREE))
 		return 0;	/* caller does not care about device status */
 
-	if (!is_loopdev(lc->device)) {
-		DBG(ITER, ul_debugobj(&lc->iter, "%s does not exist", lc->device));
-		return -errno;
-	}
-
-	DBG(ITER, ul_debugobj(&lc->iter, "%s exist", lc->device));
-
 	used = loopcxt_get_offset(lc, NULL) == 0;
 
 	if ((lc->iter.flags & LOOPITER_FL_USED) && used)
diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c
index 0ca910ae3347..b45cc2ee8f3c 100644
--- a/sys-utils/losetup.c
+++ b/sys-utils/losetup.c
@@ -653,7 +653,7 @@ static int create_loop(struct loopdev_cxt *lc,
 		}
 
 		/* errors */
-		errpre = hasdev && loopcxt_get_fd(lc) < 0 ?
+		errpre = hasdev && lc->fd < 0 ?
 				 loopcxt_get_device(lc) : file;
 		warn(_("%s: failed to set up loop device"), errpre);
 		break;
@@ -741,8 +741,7 @@ int main(int argc, char **argv)
 			break;
 		case 'c':
 			act = A_SET_CAPACITY;
-			if (!is_loopdev(optarg) ||
-			    loopcxt_set_device(&lc, optarg))
+			if (loopcxt_set_device(&lc, optarg))
 				err(EXIT_FAILURE, _("%s: failed to use device"),
 						optarg);
 			break;
@@ -754,8 +753,7 @@ int main(int argc, char **argv)
 			break;
 		case 'd':
 			act = A_DELETE;
-			if (!is_loopdev(optarg) ||
-			    loopcxt_set_device(&lc, optarg))
+			if (loopcxt_set_device(&lc, optarg))
 				err(EXIT_FAILURE, _("%s: failed to use device"),
 						optarg);
 			break;
@@ -883,8 +881,7 @@ int main(int argc, char **argv)
 		else
 			act = A_SHOW_ONE;
 
-		if (!is_loopdev(argv[optind]) ||
-		    loopcxt_set_device(&lc, argv[optind]))
+		if (loopcxt_set_device(&lc, argv[optind]))
 			err(EXIT_FAILURE, _("%s: failed to use device"),
 					argv[optind]);
 		optind++;
@@ -935,8 +932,7 @@ int main(int argc, char **argv)
 	case A_DELETE:
 		res = delete_loop(&lc);
 		while (optind < argc) {
-			if (!is_loopdev(argv[optind]) ||
-			    loopcxt_set_device(&lc, argv[optind]))
+			if (loopcxt_set_device(&lc, argv[optind]))
 				warn(_("%s: failed to use device"),
 						argv[optind]);
 			optind++;
-- 
2.39.3




[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux