2005-04-17 06:20:36 +08:00
|
|
|
#ifndef _LINUX_LOOP_H
|
|
|
|
#define _LINUX_LOOP_H
|
|
|
|
|
|
|
|
/*
|
|
|
|
* include/linux/loop.h
|
|
|
|
*
|
|
|
|
* Written by Theodore Ts'o, 3/29/93.
|
|
|
|
*
|
|
|
|
* Copyright 1993 by Theodore Ts'o. Redistribution of this file is
|
|
|
|
* permitted under the GNU General Public License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define LO_NAME_SIZE 64
|
|
|
|
#define LO_KEY_SIZE 32
|
|
|
|
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
#include <linux/bio.h>
|
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <linux/spinlock.h>
|
2006-03-23 19:00:38 +08:00
|
|
|
#include <linux/mutex.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Possible states of device */
|
|
|
|
enum {
|
|
|
|
Lo_unbound,
|
|
|
|
Lo_bound,
|
|
|
|
Lo_rundown,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct loop_func_table;
|
|
|
|
|
|
|
|
struct loop_device {
|
|
|
|
int lo_number;
|
|
|
|
int lo_refcnt;
|
|
|
|
loff_t lo_offset;
|
|
|
|
loff_t lo_sizelimit;
|
|
|
|
int lo_flags;
|
|
|
|
int (*transfer)(struct loop_device *, int cmd,
|
|
|
|
struct page *raw_page, unsigned raw_off,
|
|
|
|
struct page *loop_page, unsigned loop_off,
|
|
|
|
int size, sector_t real_block);
|
|
|
|
char lo_file_name[LO_NAME_SIZE];
|
|
|
|
char lo_crypt_name[LO_NAME_SIZE];
|
|
|
|
char lo_encrypt_key[LO_KEY_SIZE];
|
|
|
|
int lo_encrypt_key_size;
|
|
|
|
struct loop_func_table *lo_encryption;
|
|
|
|
__u32 lo_init[2];
|
|
|
|
uid_t lo_key_owner; /* Who set the key */
|
|
|
|
int (*ioctl)(struct loop_device *, int cmd,
|
|
|
|
unsigned long arg);
|
|
|
|
|
|
|
|
struct file * lo_backing_file;
|
|
|
|
struct block_device *lo_device;
|
|
|
|
unsigned lo_blocksize;
|
|
|
|
void *key_data;
|
|
|
|
|
2005-10-21 15:22:34 +08:00
|
|
|
gfp_t old_gfp_mask;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
spinlock_t lo_lock;
|
2009-04-17 14:41:21 +08:00
|
|
|
struct bio_list lo_bio_list;
|
2005-04-17 06:20:36 +08:00
|
|
|
int lo_state;
|
2006-03-23 19:00:38 +08:00
|
|
|
struct mutex lo_ctl_mutex;
|
2006-09-29 16:59:11 +08:00
|
|
|
struct task_struct *lo_thread;
|
|
|
|
wait_queue_head_t lo_event;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-07-24 09:44:00 +08:00
|
|
|
struct request_queue *lo_queue;
|
2007-05-08 15:28:20 +08:00
|
|
|
struct gendisk *lo_disk;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* __KERNEL__ */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop flags
|
|
|
|
*/
|
|
|
|
enum {
|
|
|
|
LO_FLAGS_READ_ONLY = 1,
|
2008-02-06 17:36:27 +08:00
|
|
|
LO_FLAGS_AUTOCLEAR = 4,
|
loop: always allow userspace partitions and optionally support automatic scanning
Automatic partition scanning can be requested individually per loop
device during its setup by setting LO_FLAGS_PARTSCAN. By default, no
partition tables are scanned.
Userspace can now always add and remove partitions from all loop
devices, regardless if the in-kernel partition scanner is enabled or
not.
The needed partition minor numbers are allocated from the extended
minors space, the main loop device numbers will continue to match the
loop minors, regardless of the number of partitions used.
# grep . /sys/class/block/loop1/loop/*
/sys/block/loop1/loop/autoclear:0
/sys/block/loop1/loop/backing_file:/home/kay/data/stuff/part.img
/sys/block/loop1/loop/offset:0
/sys/block/loop1/loop/partscan:1
/sys/block/loop1/loop/sizelimit:0
# ls -l /dev/loop*
brw-rw---- 1 root disk 7, 0 Aug 14 20:22 /dev/loop0
brw-rw---- 1 root disk 7, 1 Aug 14 20:23 /dev/loop1
brw-rw---- 1 root disk 259, 0 Aug 14 20:23 /dev/loop1p1
brw-rw---- 1 root disk 259, 1 Aug 14 20:23 /dev/loop1p2
brw-rw---- 1 root disk 7, 99 Aug 14 20:23 /dev/loop99
brw-rw---- 1 root disk 259, 2 Aug 14 20:23 /dev/loop99p1
brw-rw---- 1 root disk 259, 3 Aug 14 20:23 /dev/loop99p2
crw------T 1 root root 10, 237 Aug 14 20:22 /dev/loop-control
Cc: Karel Zak <kzak@redhat.com>
Cc: Davidlohr Bueso <dave@gnu.org>
Acked-By: Tejun Heo <tj@kernel.org>
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
2011-08-24 02:12:04 +08:00
|
|
|
LO_FLAGS_PARTSCAN = 8,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#include <asm/posix_types.h> /* for __kernel_old_dev_t */
|
2009-01-16 05:51:26 +08:00
|
|
|
#include <linux/types.h> /* for __u64 */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Backwards compatibility version */
|
|
|
|
struct loop_info {
|
|
|
|
int lo_number; /* ioctl r/o */
|
|
|
|
__kernel_old_dev_t lo_device; /* ioctl r/o */
|
|
|
|
unsigned long lo_inode; /* ioctl r/o */
|
|
|
|
__kernel_old_dev_t lo_rdevice; /* ioctl r/o */
|
|
|
|
int lo_offset;
|
|
|
|
int lo_encrypt_type;
|
|
|
|
int lo_encrypt_key_size; /* ioctl w/o */
|
|
|
|
int lo_flags; /* ioctl r/o */
|
|
|
|
char lo_name[LO_NAME_SIZE];
|
|
|
|
unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
|
|
|
|
unsigned long lo_init[2];
|
|
|
|
char reserved[4];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct loop_info64 {
|
|
|
|
__u64 lo_device; /* ioctl r/o */
|
|
|
|
__u64 lo_inode; /* ioctl r/o */
|
|
|
|
__u64 lo_rdevice; /* ioctl r/o */
|
|
|
|
__u64 lo_offset;
|
|
|
|
__u64 lo_sizelimit;/* bytes, 0 == max available */
|
|
|
|
__u32 lo_number; /* ioctl r/o */
|
|
|
|
__u32 lo_encrypt_type;
|
|
|
|
__u32 lo_encrypt_key_size; /* ioctl w/o */
|
|
|
|
__u32 lo_flags; /* ioctl r/o */
|
|
|
|
__u8 lo_file_name[LO_NAME_SIZE];
|
|
|
|
__u8 lo_crypt_name[LO_NAME_SIZE];
|
|
|
|
__u8 lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
|
|
|
|
__u64 lo_init[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop filter types
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define LO_CRYPT_NONE 0
|
|
|
|
#define LO_CRYPT_XOR 1
|
|
|
|
#define LO_CRYPT_DES 2
|
|
|
|
#define LO_CRYPT_FISH2 3 /* Twofish encryption */
|
|
|
|
#define LO_CRYPT_BLOW 4
|
|
|
|
#define LO_CRYPT_CAST128 5
|
|
|
|
#define LO_CRYPT_IDEA 6
|
|
|
|
#define LO_CRYPT_DUMMY 9
|
|
|
|
#define LO_CRYPT_SKIPJACK 10
|
|
|
|
#define LO_CRYPT_CRYPTOAPI 18
|
|
|
|
#define MAX_LO_CRYPT 20
|
|
|
|
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
/* Support for loadable transfer modules */
|
|
|
|
struct loop_func_table {
|
|
|
|
int number; /* filter type */
|
|
|
|
int (*transfer)(struct loop_device *lo, int cmd,
|
|
|
|
struct page *raw_page, unsigned raw_off,
|
|
|
|
struct page *loop_page, unsigned loop_off,
|
|
|
|
int size, sector_t real_block);
|
|
|
|
int (*init)(struct loop_device *, const struct loop_info64 *);
|
|
|
|
/* release is called from loop_unregister_transfer or clr_fd */
|
|
|
|
int (*release)(struct loop_device *);
|
|
|
|
int (*ioctl)(struct loop_device *, int cmd, unsigned long arg);
|
|
|
|
struct module *owner;
|
|
|
|
};
|
|
|
|
|
|
|
|
int loop_register_transfer(struct loop_func_table *funcs);
|
|
|
|
int loop_unregister_transfer(int number);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* IOCTL commands --- we will commandeer 0x4C ('L')
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define LOOP_SET_FD 0x4C00
|
|
|
|
#define LOOP_CLR_FD 0x4C01
|
|
|
|
#define LOOP_SET_STATUS 0x4C02
|
|
|
|
#define LOOP_GET_STATUS 0x4C03
|
|
|
|
#define LOOP_SET_STATUS64 0x4C04
|
|
|
|
#define LOOP_GET_STATUS64 0x4C05
|
|
|
|
#define LOOP_CHANGE_FD 0x4C06
|
loop: add ioctl to resize a loop device
Add the ability to 'resize' the loop device on the fly.
One practical application is a loop file with XFS filesystem, already
mounted: You can easily enlarge the file (append some bytes) and then call
ioctl(fd, LOOP_SET_CAPACITY, new); The loop driver will learn about the
new size and you can use xfs_growfs later on, which will allow you to use
full capacity of the loop file without the need to unmount.
Test app:
#include <linux/fs.h>
#include <linux/loop.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define _GNU_SOURCE
#include <getopt.h>
char *me;
void usage(FILE *f)
{
fprintf(f, "%s [options] loop_dev [backend_file]\n"
"-s, --set new_size_in_bytes\n"
"\twhen backend_file is given, "
"it will be expanded too while keeping the original contents\n",
me);
}
struct option opts[] = {
{
.name = "set",
.has_arg = 1,
.flag = NULL,
.val = 's'
},
{
.name = "help",
.has_arg = 0,
.flag = NULL,
.val = 'h'
}
};
void err_size(char *name, __u64 old)
{
fprintf(stderr, "size must be larger than current %s (%llu)\n",
name, old);
}
int main(int argc, char *argv[])
{
int fd, err, c, i, bfd;
ssize_t ssz;
size_t sz;
__u64 old, new, append;
char a[BUFSIZ];
struct stat st;
FILE *out;
char *backend, *dev;
err = EINVAL;
out = stderr;
me = argv[0];
new = 0;
while ((c = getopt_long(argc, argv, "s:h", opts, &i)) != -1) {
switch (c) {
case 's':
errno = 0;
new = strtoull(optarg, NULL, 0);
if (errno) {
err = errno;
perror(argv[i]);
goto out;
}
break;
case 'h':
err = 0;
out = stdout;
goto err;
default:
perror(argv[i]);
goto err;
}
}
if (optind < argc)
dev = argv[optind++];
else
goto err;
fd = open(dev, O_RDONLY);
if (fd < 0) {
err = errno;
perror(dev);
goto out;
}
err = ioctl(fd, BLKGETSIZE64, &old);
if (err) {
err = errno;
perror("ioctl BLKGETSIZE64");
goto out;
}
if (!new) {
printf("%llu\n", old);
goto out;
}
if (new < old) {
err = EINVAL;
err_size(dev, old);
goto out;
}
if (optind < argc) {
backend = argv[optind++];
bfd = open(backend, O_WRONLY|O_APPEND);
if (bfd < 0) {
err = errno;
perror(backend);
goto out;
}
err = fstat(bfd, &st);
if (err) {
err = errno;
perror(backend);
goto out;
}
if (new < st.st_size) {
err = EINVAL;
err_size(backend, st.st_size);
goto out;
}
append = new - st.st_size;
sz = sizeof(a);
while (append > 0) {
if (append < sz)
sz = append;
ssz = write(bfd, a, sz);
if (ssz != sz) {
err = errno;
perror(backend);
goto out;
}
append -= sz;
}
err = fsync(bfd);
if (err) {
err = errno;
perror(backend);
goto out;
}
}
err = ioctl(fd, LOOP_SET_CAPACITY, new);
if (err) {
err = errno;
perror("ioctl LOOP_SET_CAPACITY");
}
goto out;
err:
usage(out);
out:
return err;
}
Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp>
Signed-off-by: Tomas Matejicek <tomas@slax.org>
Cc: <util-linux-ng@vger.kernel.org>
Cc: Karel Zak <kzak@redhat.com>
Cc: Jens Axboe <jens.axboe@oracle.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Akinobu Mita <akinobu.mita@gmail.com>
Cc: <linux-api@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-04-01 06:23:43 +08:00
|
|
|
#define LOOP_SET_CAPACITY 0x4C07
|
2005-04-17 06:20:36 +08:00
|
|
|
|
loop: add management interface for on-demand device allocation
Loop devices today have a fixed pre-allocated number of usually 8.
The number can only be changed at module init time. To find a free
device to use, /dev/loop%i needs to be scanned, and all devices need
to be opened until a free one is possibly found.
This adds a new /dev/loop-control device node, that allows to
dynamically find or allocate a free device, and to add and remove loop
devices from the running system:
LOOP_CTL_ADD adds a specific device. Arg is the number
of the device. It returns the device i or a negative
error code.
LOOP_CTL_REMOVE removes a specific device, Arg is the
number the device. It returns the device i or a negative
error code.
LOOP_CTL_GET_FREE finds the next unbound device or allocates
a new one. No arg is given. It returns the device i or a
negative error code.
The loop kernel module gets automatically loaded when
/dev/loop-control is accessed the first time. The alias
specified in the module, instructs udev to create this
'dead' device node, even when the module is not loaded.
Example:
cfd = open("/dev/loop-control", O_RDWR);
# add a new specific loop device
err = ioctl(cfd, LOOP_CTL_ADD, devnr);
# remove a specific loop device
err = ioctl(cfd, LOOP_CTL_REMOVE, devnr);
# find or allocate a free loop device to use
devnr = ioctl(cfd, LOOP_CTL_GET_FREE);
sprintf(loopname, "/dev/loop%i", devnr);
ffd = open("backing-file", O_RDWR);
lfd = open(loopname, O_RDWR);
err = ioctl(lfd, LOOP_SET_FD, ffd);
Cc: Tejun Heo <tj@kernel.org>
Cc: Karel Zak <kzak@redhat.com>
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
2011-08-01 04:08:04 +08:00
|
|
|
/* /dev/loop-control interface */
|
|
|
|
#define LOOP_CTL_ADD 0x4C80
|
|
|
|
#define LOOP_CTL_REMOVE 0x4C81
|
|
|
|
#define LOOP_CTL_GET_FREE 0x4C82
|
2005-04-17 06:20:36 +08:00
|
|
|
#endif
|