/dev/loop-control
システム起動時、マイナ番号0から7の8つの/dev/loopデバイスが作成されますが、/dev/loop-controlでloopデバイスの追加/削除をユザー空間から可能とします。
サンプル
実行結果
loopデバイスはloop_index_idrでリスト管理されています。
LOOP_CTL_ADDで追加されたデバイスと初期で作成されているデバイスとの違いはなく、LOOP_CTL_REMOVEはシステム起動時に作成されているデバイス(loop0からloop7)にも適用されます。
サンプル
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define LOOP_CTL_ADD 0x4C80 #define LOOP_CTL_REMOVE 0x4C81 #define LOOP_CTL_GET_FREE 0x4C82 void main(int argc, char *argv[]) { int lfd, ret; lfd = open("/dev/loop-control", O_RDWR); if (!strcmp(argv[1], "LOOP_CTL_ADD")) { ret = ioctl(lfd, LOOP_CTL_ADD, atoi(argv[2])); printf("add /dev/loop%d\n", ret); } else { if (!strcmp(argv[1], "LOOP_CTL_REMOVE")) { ret = ioctl(lfd, LOOP_CTL_REMOVE, atoi(argv[2])); printf("rm /dev/loop%d\n", ret); } else { if (!strcmp(argv[1], "LOOP_CTL_GET_FREE")) { ret = ioctl(lfd, LOOP_CTL_GET_FREE, 0); printf("unused loop/dev/loop%d\n", ret); } else { printf("argv err\n"); } } } close(lfd); }
実行結果
[root@localhost north]# ls /dev/loop* /dev/loop-control /dev/loop1 /dev/loop3 /dev/loop5 /dev/loop7 /dev/loop0 /dev/loop2 /dev/loop4 /dev/loop6
[root@localhost north]# ./a.out LOOP_CTL_ADD 8 add /dev/loop8 [root@localhost north]# ls /dev/loop* /dev/loop-control /dev/loop1 /dev/loop3 /dev/loop5 /dev/loop7 /dev/loop0 /dev/loop2 /dev/loop4 /dev/loop6 /dev/loop8
[root@localhost north]# ./a.out LOOP_CTL_REMOVE 8 rm /dev/loop8 [root@localhost north]# ls /dev/loop* /dev/loop-control /dev/loop1 /dev/loop3 /dev/loop5 /dev/loop7 /dev/loop0 /dev/loop2 /dev/loop4 /dev/loop6
[root@localhost north]# ./a.out LOOP_CTL_GET_FREE unused loop/dev/loop0 [root@localhost north]# mount -o loop disk /mnt4 [root@localhost north]# df | grep loop /dev/loop0 1011 27 933 3% /mnt4 [root@localhost north]# ./a.out LOOP_CTL_GET_FREE unused loop/dev/loop1実装
loopデバイスはloop_index_idrでリスト管理されています。
static struct idr loop_index_idr static const struct file_operations loop_ctl_fops = { .open = nonseekable_open, .unlocked_ioctl = loop_control_ioctl, .compat_ioctl = loop_control_ioctl, .owner = THIS_MODULE, .llseek = noop_llseek, }; static struct miscdevice loop_misc = { .minor = LOOP_CTRL_MINOR, .name = "loop-control", .fops = &loop_ctl_fops, }; static long loop_control_ioctl(struct file *file, unsigned int cmd, unsigned long parm) { struct loop_device *lo; int ret = -ENOSYS; mutex_lock(&loop_index_mutex); switch (cmd) { case LOOP_CTL_ADD: ret = loop_lookup(&lo, parm); if (ret >= 0) { ret = -EEXIST; break; } ret = loop_add(&lo, parm); break; case LOOP_CTL_REMOVE: ret = loop_lookup(&lo, parm); if (ret < 0) break; mutex_lock(&lo->lo_ctl_mutex); if (lo->lo_state != Lo_unbound) { ret = -EBUSY; mutex_unlock(&lo->lo_ctl_mutex); break; } if (lo->lo_refcnt > 0) { ret = -EBUSY; mutex_unlock(&lo->lo_ctl_mutex); break; } lo->lo_disk->private_data = NULL; mutex_unlock(&lo->lo_ctl_mutex); idr_remove(&loop_index_idr, lo->lo_number); loop_remove(lo); break; case LOOP_CTL_GET_FREE: ret = loop_lookup(&lo, -1); if (ret >= 0) break; ret = loop_add(&lo, -1); } mutex_unlock(&loop_index_mutex); return ret; } static int loop_lookup(struct loop_device **l, int i) { struct loop_device *lo; int ret = -ENODEV; if (i < 0) { int err; err = idr_for_each(&loop_index_idr, &find_free_cb, &lo); if (err == 1) { *l = lo; ret = lo->lo_number; } goto out; } lo = idr_find(&loop_index_idr, i); if (lo) { *l = lo; ret = lo->lo_number; } out: return ret; }
補足
LOOP_CTL_GET_FREEで未使用なデバイスが取得できない時、新規にデバイスを作成しそのマイナ番号を返します。LOOP_CTL_ADDで追加されたデバイスと初期で作成されているデバイスとの違いはなく、LOOP_CTL_REMOVEはシステム起動時に作成されているデバイス(loop0からloop7)にも適用されます。