diff --git a/kmod/src/ioctl.c b/kmod/src/ioctl.c index 664e7f22..a947bc6a 100644 --- a/kmod/src/ioctl.c +++ b/kmod/src/ioctl.c @@ -326,30 +326,19 @@ static long scoutfs_ioc_release(struct file *file, unsigned long arg) struct scoutfs_ioctl_release args; loff_t start; loff_t end_inc; - u64 iblock; - u64 end_block; - u64 len; int ret; if (copy_from_user(&args, (void __user *)arg, sizeof(args))) return -EFAULT; - trace_printk("offset %llu count %llu vers %llu\n", - args.offset, args.count, args.data_version); + trace_printk("block %llu count %llu vers %llu\n", + args.block, args.count, args.data_version); if (args.count == 0) return 0; - if ((args.offset + args.count) < args.offset) + if ((args.block + args.count) < args.block) return -EINVAL; - start = round_up(args.offset, SCOUTFS_BLOCK_SIZE); - end_inc = round_down(args.offset + args.count, SCOUTFS_BLOCK_SIZE) - 1; - if (end_inc < start) - return 0; - - iblock = start >> SCOUTFS_BLOCK_SHIFT; - end_block = end_inc >> SCOUTFS_BLOCK_SHIFT; - len = end_block - iblock + 1; ret = mnt_want_write_file(file); if (ret) @@ -375,10 +364,12 @@ static long scoutfs_ioc_release(struct file *file, unsigned long arg) inode_dio_wait(inode); /* drop all clean and dirty cached blocks in the range */ + start = args.block << SCOUTFS_BLOCK_SHIFT; + end_inc = ((args.block + args.count) << SCOUTFS_BLOCK_SHIFT) - 1; truncate_inode_pages_range(&inode->i_data, start, end_inc); - ret = scoutfs_data_truncate_items(sb, scoutfs_ino(inode), iblock, len, - true); + ret = scoutfs_data_truncate_items(sb, scoutfs_ino(inode), args.block, + args.count, true); out: mutex_unlock(&inode->i_mutex); mnt_drop_write_file(file); diff --git a/kmod/src/ioctl.h b/kmod/src/ioctl.h index 0dcb6bc7..c8a267b5 100644 --- a/kmod/src/ioctl.h +++ b/kmod/src/ioctl.h @@ -124,8 +124,30 @@ struct scoutfs_ioctl_ino_path { #define SCOUTFS_IOC_DATA_VERSION _IOW(SCOUTFS_IOCTL_MAGIC, 4, __u64) +/* + * "Release" a contiguous range of logical blocks of file data. + * Released blocks are removed from the file system like truncation, but + * an offline record is left behind to trigger demand staging if the + * file is read. + * + * The starting block offset and number of blocks to release are in + * units 4KB blocks. + * + * The specified range can extend past i_size and can straddle sparse + * regions or blocks that are already offline. The only change it makes + * is to free and mark offline any existing blocks that intersect with + * the region. + * + * Returns 0 if the operation succeeds. If an error is returned then + * some partial region of the blocks in the region may have been marked + * offline. + * + * If the operation succeeds then inode metadata that reflects file data + * contents are not updated. This is intended to be transparent to the + * presentation of the data in the file. + */ struct scoutfs_ioctl_release { - __u64 offset; + __u64 block; __u64 count; __u64 data_version; } __packed;