diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c index d30bb4bc477c..7d2276c8316d 100644 --- a/fs/incfs/data_mgmt.c +++ b/fs/incfs/data_mgmt.c @@ -437,6 +437,7 @@ int incfs_get_filled_blocks(struct data_file *df, if (end_index > df->df_total_block_count) end_index = df->df_total_block_count; arg->total_blocks_out = df->df_total_block_count; + arg->data_blocks_out = df->df_data_block_count; if (df->df_header_flags & INCFS_FILE_COMPLETE) { pr_debug("File marked full, fast get_filled_blocks"); diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index 2708a99f0ae2..9fcc3352ee37 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -1447,6 +1447,9 @@ static long ioctl_get_filled_blocks(struct file *f, void __user *arg) if (!df) return -EINVAL; + if ((uintptr_t)f->private_data != CAN_FILL) + return -EPERM; + if (copy_from_user(&args, args_usr_ptr, sizeof(args)) > 0) return -EINVAL; diff --git a/include/uapi/linux/incrementalfs.h b/include/uapi/linux/incrementalfs.h index 0fb1c86d2f9d..ac775b64bdcf 100644 --- a/include/uapi/linux/incrementalfs.h +++ b/include/uapi/linux/incrementalfs.h @@ -328,6 +328,9 @@ struct incfs_get_filled_blocks_args { /* Actual number of blocks in file */ __u32 total_blocks_out; + /* The number of data blocks in file */ + __u32 data_blocks_out; + /* Number of bytes written to range buffer */ __u32 range_buffer_size_out; diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c index f1a239f6376d..639e2fb1544c 100644 --- a/tools/testing/selftests/filesystems/incfs/incfs_test.c +++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c @@ -2189,12 +2189,29 @@ static int validate_ranges(const char *mount_dir, struct test_file *file) int error = TEST_SUCCESS; int i; int range_cnt; + int cmd_fd = -1; + struct incfs_permit_fill permit_fill; fd = open(filename, O_RDONLY); free(filename); if (fd <= 0) return TEST_FAILURE; + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); + if (error != -1 || errno != EPERM) { + ksft_print_msg("INCFS_IOC_GET_FILLED_BLOCKS not blocked\n"); + error = -EPERM; + goto out; + } + + cmd_fd = open_commands_file(mount_dir); + permit_fill.file_descriptor = fd; + if (ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) { + print_error("INCFS_IOC_PERMIT_FILL failed"); + return -EPERM; + goto out; + } + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); if (error && errno != ERANGE) goto out; @@ -2212,6 +2229,11 @@ static int validate_ranges(const char *mount_dir, struct test_file *file) goto out; } + if (fba.data_blocks_out != block_cnt) { + error = -EINVAL; + goto out; + } + range_cnt = (block_cnt + 3) / 4; if (range_cnt > 128) range_cnt = 128; @@ -2282,6 +2304,7 @@ static int validate_ranges(const char *mount_dir, struct test_file *file) out: close(fd); + close(cmd_fd); return error; } @@ -2392,6 +2415,7 @@ failure: static int validate_hash_ranges(const char *mount_dir, struct test_file *file) { + int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; char *filename = concat_file_name(mount_dir, file->name); int fd; struct incfs_filled_range ranges[128]; @@ -2402,6 +2426,8 @@ static int validate_hash_ranges(const char *mount_dir, struct test_file *file) int error = TEST_SUCCESS; int file_blocks = (file->size + INCFS_DATA_FILE_BLOCK_SIZE - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int cmd_fd = -1; + struct incfs_permit_fill permit_fill; if (file->size <= 4096 / 32 * 4096) return 0; @@ -2411,10 +2437,35 @@ static int validate_hash_ranges(const char *mount_dir, struct test_file *file) if (fd <= 0) return TEST_FAILURE; + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); + if (error != -1 || errno != EPERM) { + ksft_print_msg("INCFS_IOC_GET_FILLED_BLOCKS not blocked\n"); + error = -EPERM; + goto out; + } + + cmd_fd = open_commands_file(mount_dir); + permit_fill.file_descriptor = fd; + if (ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) { + print_error("INCFS_IOC_PERMIT_FILL failed"); + return -EPERM; + goto out; + } + error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba); if (error) goto out; + if (fba.total_blocks_out <= block_cnt) { + error = -EINVAL; + goto out; + } + + if (fba.data_blocks_out != block_cnt) { + error = -EINVAL; + goto out; + } + if (fba.range_buffer_size_out != sizeof(struct incfs_filled_range)) { error = -EINVAL; goto out; @@ -2427,6 +2478,7 @@ static int validate_hash_ranges(const char *mount_dir, struct test_file *file) } out: + close(cmd_fd); close(fd); return error; }