diff -Nur linux-2.4.20/drivers/block/loop.c linux-2.4.20-kd/drivers/block/loop.c --- linux-2.4.20/drivers/block/loop.c Fri Nov 29 00:53:12 2002 +++ linux-2.4.20-kd/drivers/block/loop.c Thu Feb 6 17:33:48 2003 @@ -299,14 +299,32 @@ return bs; } +static inline int loop_get_shift(int size) +{ + int i = -1; + + while (size) { + i++; + size >>= 1; + } + return i; +} + static inline unsigned long loop_get_iv(struct loop_device *lo, unsigned long sector) { int bs = loop_get_bs(lo); unsigned long offset, IV; + int shift = loop_get_shift(bs); + if ((bs<512)||!(bs&(bs-1))) BUG(); + + /* IV = sector / (bs >> 9) + lo->lo_offset / bs; offset = ((sector % (bs >> 9)) << 9) + lo->lo_offset % bs; + */ + IV = (sector >> (shift - 9)) + (lo->lo_offset >> shift); + offset = ((sector << 9) & (bs-512)) + (lo->lo_offset & (bs - 1)); if (offset >= bs) IV++; @@ -775,49 +793,88 @@ return 0; } -static int loop_set_status(struct loop_device *lo, struct loop_info *arg) +static int do_loop_set_status(struct loop_device *lo, struct loop_info *info) { - struct loop_info info; int err; unsigned int type; - - if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && - !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (lo->lo_state != Lo_bound) - return -ENXIO; - if (copy_from_user(&info, arg, sizeof (struct loop_info))) - return -EFAULT; - if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE) + if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; - type = info.lo_encrypt_type; + type = info->lo_encrypt_type; if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL) return -EINVAL; - if (type == LO_CRYPT_XOR && info.lo_encrypt_key_size == 0) + if (type == LO_CRYPT_XOR && info->lo_encrypt_key_size == 0) return -EINVAL; err = loop_release_xfer(lo); if (!err) - err = loop_init_xfer(lo, type, &info); + err = loop_init_xfer(lo, type, info); if (err) return err; - lo->lo_offset = info.lo_offset; - strncpy(lo->lo_name, info.lo_name, LO_NAME_SIZE); + lo->lo_offset = info->lo_offset; + strncpy(lo->lo_name, info->lo_name, LO_NAME_SIZE); lo->transfer = xfer_funcs[type]->transfer; lo->ioctl = xfer_funcs[type]->ioctl; - lo->lo_encrypt_key_size = info.lo_encrypt_key_size; - lo->lo_init[0] = info.lo_init[0]; - lo->lo_init[1] = info.lo_init[1]; - if (info.lo_encrypt_key_size) { - memcpy(lo->lo_encrypt_key, info.lo_encrypt_key, - info.lo_encrypt_key_size); + lo->lo_encrypt_key_size = info->lo_encrypt_key_size; + lo->lo_init[0] = info->lo_init[0]; + lo->lo_init[1] = info->lo_init[1]; + if (info->lo_encrypt_key_size) { + memcpy(lo->lo_encrypt_key, info->lo_encrypt_key, + info->lo_encrypt_key_size); lo->lo_key_owner = current->uid; } figure_loop_size(lo); return 0; } +static int loop_set_status(struct loop_device *lo, struct loop_info *arg) +{ + struct loop_info info; + + if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + if (lo->lo_state != Lo_bound) + return -ENXIO; + if (copy_from_user(&info, arg, sizeof (info))) + return -EFAULT; + + return do_loop_set_status(lo,&info); +} + +static int loop_set_status_old(struct loop_device *lo, struct loop_info_old *arg) +{ + struct loop_info_old info_old; + struct loop_info info; + + if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + if (lo->lo_state != Lo_bound) + return -ENXIO; + if (copy_from_user(&info_old, arg, sizeof (info_old))) + return -EFAULT; + +#define COPY(f) info.f=info_old.f + COPY(lo_number); + COPY(lo_device); + COPY(lo_inode); + COPY(lo_rdevice); + COPY(lo_offset); + COPY(lo_encrypt_type); + COPY(lo_encrypt_key_size); + COPY(lo_flags); +#undef COPY +#define COPY(f) memcpy(&(info.f),&(info_old.f),sizeof(info.f)) + COPY(lo_name); + COPY(lo_encrypt_key); + COPY(lo_init); + COPY(reserved); +#undef COPY + + return do_loop_set_status(lo,&info); +} + static int loop_get_status(struct loop_device *lo, struct loop_info *arg) { struct loop_info info; @@ -844,6 +901,32 @@ return copy_to_user(arg, &info, sizeof(info)) ? -EFAULT : 0; } +static int loop_get_status_old(struct loop_device *lo, struct loop_info_old *arg) +{ + struct loop_info_old info; + struct file *file = lo->lo_backing_file; + + if (lo->lo_state != Lo_bound) + return -ENXIO; + if (!arg) + return -EINVAL; + memset(&info, 0, sizeof(info)); + info.lo_number = lo->lo_number; + info.lo_device = kdev_t_to_nr(file->f_dentry->d_inode->i_dev); + info.lo_inode = file->f_dentry->d_inode->i_ino; + info.lo_rdevice = kdev_t_to_nr(lo->lo_device); + info.lo_offset = lo->lo_offset; + info.lo_flags = lo->lo_flags; + strncpy(info.lo_name, lo->lo_name, LO_NAME_SIZE); + info.lo_encrypt_type = lo->lo_encrypt_type; + if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { + info.lo_encrypt_key_size = lo->lo_encrypt_key_size; + memcpy(info.lo_encrypt_key, lo->lo_encrypt_key, + lo->lo_encrypt_key_size); + } + return copy_to_user(arg, &info, sizeof(info)) ? -EFAULT : 0; +} + static int lo_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { @@ -874,6 +957,12 @@ break; case LOOP_GET_STATUS: err = loop_get_status(lo, (struct loop_info *) arg); + break; + case LOOP_SET_STATUS_OLD: + err = loop_set_status_old(lo, (struct loop_info_old *) arg); + break; + case LOOP_GET_STATUS_OLD: + err = loop_get_status_old(lo, (struct loop_info_old *) arg); break; case BLKGETSIZE: if (lo->lo_state != Lo_bound) { diff -Nur linux-2.4.20/include/linux/loop.h linux-2.4.20-kd/include/linux/loop.h --- linux-2.4.20/include/linux/loop.h Mon Sep 17 22:16:30 2001 +++ linux-2.4.20-kd/include/linux/loop.h Thu Feb 6 17:33:56 2003 @@ -28,7 +28,7 @@ int lo_number; int lo_refcnt; kdev_t lo_device; - int lo_offset; + loff_t lo_offset; int lo_encrypt_type; int lo_encrypt_key_size; int lo_flags; @@ -99,6 +99,21 @@ dev_t lo_device; /* ioctl r/o */ unsigned long lo_inode; /* ioctl r/o */ dev_t lo_rdevice; /* ioctl r/o */ + loff_t 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_info_old { + int lo_number; /* ioctl r/o */ + dev_t lo_device; /* ioctl r/o */ + unsigned long lo_inode; /* ioctl r/o */ + dev_t lo_rdevice; /* ioctl r/o */ int lo_offset; int lo_encrypt_type; int lo_encrypt_key_size; /* ioctl w/o */ @@ -147,9 +162,11 @@ * 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_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 +#define LOOP_SET_STATUS_OLD 0x4C02 +#define LOOP_GET_STATUS_OLD 0x4C03 +#define LOOP_SET_STATUS 0x4C42 +#define LOOP_GET_STATUS 0x4C43 #endif