]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
losetup: support ioctl cmd of LOOP_SET_DIRECT_IO
authorMing Lei <tom.leiming@gmail.com>
Tue, 17 Nov 2015 14:32:47 +0000 (22:32 +0800)
committerKarel Zak <kzak@redhat.com>
Thu, 19 Nov 2015 10:27:36 +0000 (11:27 +0100)
From v4.4, linux kernel starts to support direct I/O and
AIO to backing file for loop driver, so allow losetup to
enable the feature by using LOOP_SET_DIRECT_IO ioctl cmd.

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
include/loopdev.h
lib/loopdev.c
sys-utils/losetup.c

index 573a5699d4396fd5f38ebfae8c71b7032f5351f3..9a7f6ba69db45ca67d1a631c00328683899f3d96 100644 (file)
@@ -23,6 +23,7 @@
 #define LOOP_GET_STATUS64      0x4C05
 /* #define LOOP_CHANGE_FD      0x4C06 */
 #define LOOP_SET_CAPACITY      0x4C07
+#define LOOP_SET_DIRECT_IO     0x4C08
 
 /* /dev/loop-control interface */
 #ifndef LOOP_CTL_ADD
@@ -164,6 +165,7 @@ extern int loopcxt_next(struct loopdev_cxt *lc);
 extern int loopcxt_setup_device(struct loopdev_cxt *lc);
 extern int loopcxt_delete_device(struct loopdev_cxt *lc);
 extern int loopcxt_set_capacity(struct loopdev_cxt *lc);
+extern int loopcxt_set_dio(struct loopdev_cxt *lc, unsigned long use_dio);
 
 int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset);
 int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit);
index fe047cdcfb6fa11236733f2ce61fe524349213a9..ff99dd444e4a068eeae2afd362821a9a22fea46d 100644 (file)
@@ -1315,6 +1315,24 @@ int loopcxt_set_capacity(struct loopdev_cxt *lc)
        return 0;
 }
 
+int loopcxt_set_dio(struct loopdev_cxt *lc, unsigned long use_dio)
+{
+       int fd = loopcxt_get_fd(lc);
+
+       if (fd < 0)
+               return -EINVAL;
+
+       /* Kernels prior to v4.4 don't support this ioctl */
+       if (ioctl(fd, LOOP_SET_DIRECT_IO, use_dio) < 0) {
+               int rc = -errno;
+               DBG(CXT, ul_debugobj(lc, "LOOP_SET_DIRECT_IO failed: %m"));
+               return rc;
+       }
+
+       DBG(CXT, ul_debugobj(lc, "direct io set"));
+       return 0;
+}
+
 int loopcxt_delete_device(struct loopdev_cxt *lc)
 {
        int fd = loopcxt_get_fd(lc);
index a68b222295df9601c3cf1a60ff2835c8d8da0422..68f77779802f24480af2c124264844e07e853b6c 100644 (file)
@@ -35,6 +35,7 @@ enum {
        A_SHOW_ONE,             /* print info about one device */
        A_FIND_FREE,            /* find first unused */
        A_SET_CAPACITY,         /* set device capacity */
+       A_SET_DIRECT_IO,        /* set accessing backing file by direct io */
 };
 
 enum {
@@ -393,6 +394,7 @@ static void usage(FILE *out)
        fputs(_("     --sizelimit <num>         device is limited to <num> bytes of the file\n"), out);
        fputs(_(" -P, --partscan                create a partitioned loop device\n"), out);
        fputs(_(" -r, --read-only               set up a read-only loop device\n"), out);
+       fputs(_("     --direct-io               open backing file with O_DIRECT\n"), out);
        fputs(_("     --show                    print device name after setup (with -f)\n"), out);
        fputs(_(" -v, --verbose                 verbose mode\n"), out);
 
@@ -446,11 +448,13 @@ int main(int argc, char **argv)
        int res = 0, showdev = 0, lo_flags = 0;
        char *outarg = NULL;
        int list = 0;
+       unsigned long use_dio = 0, set_dio = 0;
 
        enum {
                OPT_SIZELIMIT = CHAR_MAX + 1,
                OPT_SHOW,
-               OPT_RAW
+               OPT_RAW,
+               OPT_DIO
        };
        static const struct option longopts[] = {
                { "all", 0, 0, 'a' },
@@ -468,6 +472,7 @@ int main(int argc, char **argv)
                { "sizelimit", 1, 0, OPT_SIZELIMIT },
                { "partscan", 0, 0, 'P' },
                { "read-only", 0, 0, 'r' },
+               { "direct-io", 1, 0, OPT_DIO },
                { "raw", 0, 0, OPT_RAW },
                { "show", 0, 0, OPT_SHOW },
                { "verbose", 0, 0, 'v' },
@@ -557,6 +562,10 @@ int main(int argc, char **argv)
                case OPT_SHOW:
                        showdev = 1;
                        break;
+               case OPT_DIO:
+                       set_dio = 1;
+                       use_dio = strtoul_or_err(optarg, _("failed to parse dio"));
+                       break;
                case 'v':
                        break;
                case 'V':
@@ -609,8 +618,13 @@ int main(int argc, char **argv)
        if (!act && optind + 1 == argc) {
                /*
                 * losetup [--list] <device>
+                * OR
+                * losetup --direct-io DIO <device>
                 */
-               act = A_SHOW_ONE;
+               if (!set_dio)
+                       act = A_SHOW_ONE;
+               else
+                       act = A_SET_DIRECT_IO;
                if (!is_loopdev(argv[optind]) ||
                    loopcxt_set_device(&lc, argv[optind]))
                        err(EXIT_FAILURE, _("%s: failed to use device"),
@@ -695,6 +709,8 @@ int main(int argc, char **argv)
                        if (showdev)
                                printf("%s\n", loopcxt_get_device(&lc));
                        warn_size(file, sizelimit);
+                       if (set_dio)
+                               goto lo_set_dio;
                }
                break;
        }
@@ -747,6 +763,13 @@ int main(int argc, char **argv)
                        warn(_("%s: set capacity failed"),
                                loopcxt_get_device(&lc));
                break;
+       case A_SET_DIRECT_IO:
+ lo_set_dio:
+               res = loopcxt_set_dio(&lc, use_dio);
+               if (res)
+                       warn(_("%s: set direct io failed"),
+                               loopcxt_get_device(&lc));
+               break;
        default:
                usage(stderr);
                break;