scoutfs: make release block granular

The existing release interface specified byte regions to release but
that didn't match what the underlying file data mapping structure is
capable of.  What happens if you specify a single byte to release?  Does
it release the whole block?  Does it release nothing?  Does it return an
error?

By making the interface match the capability of the operation we make
the functioning of the system that much more predictable.  Callers are
forced to think about implementing their desires in terms of block
granular releasing.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2017-08-01 09:49:12 -07:00
committed by Zach Brown
parent 87ab27beb1
commit c7ad9fe772
2 changed files with 30 additions and 17 deletions
+7 -16
View File
@@ -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);
+23 -1
View File
@@ -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;