Add ioctl FITRIM.
Subsystems (3)
PATCH 1/3 Add ioctl FITRIM.
Adds an filesystem independent ioctl to allow implementation of file system batched discard support.
--- fs/ioctl.c | 31 +++++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 33 insertions(+), 0 deletions(-)
fs/ioctl.c +31 -0
@@ -540,6 +540,33 @@ static int ioctl_fsthaw(struct file *filp)return thaw_super (sb); } +static int ioctl_fstrim (struct file *filp,unsigned long arg) +{ +struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; +unsigned int minlen; +int err; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +/* If filesystem doesn't support trim feature, return. */ +if (sb->s_op->trim_fs ==NULL ) +return -EOPNOTSUPP ; + +/* If a blockdevice-backed filesystem isn't specified, return EINVAL. */ +if (sb->s_bdev ==NULL ) +return -EINVAL ; + + err =get_user (minlen, (unsigned int __user *) arg); +if (err) +return err; + + err = sb->s_op->trim_fs (minlen, sb); +if (err) +return err; +return 0 ; +} +/* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too.
@@ -590,6 +617,10 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, error =ioctl_fsthaw (filp);break ; +case FITRIM : + error =ioctl_fstrim (filp, arg); +break ; +case FS_IOC_FIEMAP :return ioctl_fiemap (filp, arg);
include/linux/fs.h +2 -0
@@ -315,6 +315,7 @@ struct inodes_stat_t {#define FIGETBSZ _IO(0x00,2)/* get the block size used for bmap */ #define FIFREEZE _IOWR('X', 119, int)/* Freeze */ #define FITHAW _IOWR('X', 120, int)/* Thaw */ +#define FITRIM _IOWR('X', 121, int)/* Trim */ #define FS_IOC_GETFLAGS _IOR('f', 1, long)#define FS_IOC_SETFLAGS _IOW('f', 2, long)
@@ -1580,6 +1581,7 @@ struct super_operations {ssize_t (*quota_write)(struct super_block *,int ,const char *,size_t ,loff_t );#endif int (*bdev_try_to_free_page)(struct super_block *,struct page *,gfp_t ); +int (*trim_fs) (unsigned int ,struct super_block *); };/*
Signature · 1 line
1.7.2
PATCH 2/3 Add batched discard support for ext3
Walk through each allocation group and trim all free extents. It can be invoked through FITRIM ioctl on the file system. The main idea is to provide a way to trim the whole file system if needed, since some SSD's may suffer from performance loss after the whole device was filled (it does not mean that fs is full!).
It search for free extents in each allocation group. When the free extent is found, blocks are marked as used and then trimmed. Afterwards these blocks are marked as free in per-group bitmap.
--- fs/ext3/balloc.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++ fs/ext3/super.c | 1 + include/linux/ext3_fs.h | 1 + 3 files changed, 219 insertions(+), 0 deletions(-)
fs/ext3/balloc.c +217 -0
@@ -20,6 +20,7 @@#include <linux/ext3_jbd.h> #include <linux/quotaops.h> #include <linux/buffer_head.h> +#include <linux/blkdev.h> /* * balloc.c contains the blocks allocation and deallocation routines
@@ -1882,3 +1883,219 @@ unsigned long ext3_bg_num_gdb(struct super_block *sb, int group)return ext3_bg_num_gdb_meta (sb,group); } + +/** +* ext3_trim_all_free -- function to trim all free space in alloc. group +* @sb: super block for file system +* @group: allocation group to trim +* @gdp: allocation group description structure +* @minblocks: minimum extent block count +* +* ext3_trim_all_free walks through group's block bitmap searching for free +* blocks. When the free block is found, it tries to allocate this block and +* consequent free block to get the biggest free extent possible, until it +* reaches any used block. Then issue a TRIM command on this extent and free +* the extent in the block bitmap. This is done until whole group is scanned. +*/ +ext3_grpblk_t ext3_trim_all_free (struct super_block *sb, +unsigned int group,ext3_grpblk_t minblocks) +{ +handle_t *handle; +ext3_grpblk_t max =EXT3_BLOCKS_PER_GROUP (sb); +ext3_grpblk_t next, count =0 , start, bit; +struct ext3_sb_info *sbi; +ext3_fsblk_t discard_block; +struct buffer_head *bitmap_bh =NULL ; +struct buffer_head *gdp_bh; +ext3_grpblk_t free_blocks; +struct ext3_group_desc *gdp; +int err =0 , ret; +ext3_grpblk_t freed; + +/* +* We will update one block bitmap, and one group descriptor +*/ + handle =ext3_journal_start_sb (sb,2 ); +if (IS_ERR (handle)) { + err =PTR_ERR (handle); +return err; + } + + bitmap_bh =read_block_bitmap (sb, group); +if (!bitmap_bh) + goto err_out; + +BUFFER_TRACE (bitmap_bh,"getting undo access" ); + err =ext3_journal_get_undo_access (handle, bitmap_bh); +if (err) + goto err_out; + + gdp =ext3_get_group_desc (sb, group, &gdp_bh); +if (!gdp) + goto err_out; + +BUFFER_TRACE (gd_bh,"get_write_access" ); + err =ext3_journal_get_write_access (handle, gdp_bh); +if (err) + goto err_out; + + free_blocks =le16_to_cpu (gdp->bg_free_blocks_count); + sbi =EXT3_SB (sb); + +/* Walk through the whole group */ + start =0 ; +while (start < max) { + + start =bitmap_search_next_usable_block (start, bitmap_bh, max); +if (start <0 ) +break ; + next = start; + +/* +* Allocate contiguous free extents by setting bits in the +* block bitmap +*/ +while (next < max + &&claim_block (sb_bgl_lock (sbi, group), + next, bitmap_bh)) { + next++; + } + +/* We did not claim any blocks */ +if (next == start) +continue ; + + discard_block = (ext3_fsblk_t )start + +ext3_group_first_block_no (sb, group); + +/* Update counters */ +spin_lock (sb_bgl_lock (sbi, group)); +le16_add_cpu (&gdp->bg_free_blocks_count, start - next); +spin_unlock (sb_bgl_lock (sbi, group)); +percpu_counter_sub (&sbi->s_freeblocks_counter, next - start); + +/* Do not issue a TRIM on extents smaller than minblocks */ +if ((next - start) < minblocks) + goto free_extent; + +/* Send the TRIM command down to the device */ + ret =sb_issue_discard (sb, discard_block, next - start); + count += (next - start); + +free_extent: + freed =0 ; + +/* +* Clear bits in the bitmap +*/ +for (bit = start; bit < next; bit++) { +BUFFER_TRACE (bitmap_bh,"clear bit" ); +if (!ext3_clear_bit_atomic (sb_bgl_lock (sbi, group), + bit, bitmap_bh->b_data)) { +ext3_error (sb, __func__, +"bit already cleared for block " E3FSBLK , + (unsigned long )bit); +BUFFER_TRACE (bitmap_bh,"bit already cleared" ); + }else { + freed++; + } + } + +/* Update couters */ +spin_lock (sb_bgl_lock (sbi, group)); +le16_add_cpu (&gdp->bg_free_blocks_count, freed); +spin_unlock (sb_bgl_lock (sbi, group)); +percpu_counter_add (&sbi->s_freeblocks_counter, next - start); + + start = next; + +if (ret ==EOPNOTSUPP ) { +ext3_warning (sb, __func__, +"discard not supported!" ); + count = -EOPNOTSUPP ; +break ; + + } + +if (signal_pending (current)) { + count = -ERESTARTSYS ; +break ; + } + +cond_resched (); + +/* No more suitable extents */ +if ((free_blocks - count) < minblocks) +break ; + } + +/* We dirtied the bitmap block */ +BUFFER_TRACE (bitmap_bh,"dirtied bitmap block" ); + err =ext3_journal_dirty_metadata (handle, bitmap_bh); + +/* And the group descriptor block */ +BUFFER_TRACE (gdp_bh,"dirtied group descriptor block" ); + ret =ext3_journal_dirty_metadata (handle, gdp_bh); +if (!err) + err = ret; + +ext3_debug ("trimmed %d blocks in the group %d\n" , + count, group); + +err_out: +if (err) { +ext3_std_error (sb, err); + count = -err; + } + +ext3_journal_stop (handle); +brelse (bitmap_bh); + +return count; +} + +/** +* ext3_trim_fs() -- trim ioctl handle function +* @minlen: minimum extent length in Bytes +* @sb: superblock for filesystem +* +* ext3_trim_fs goes through all allocation group searching for groups with more +* free space than minlen. For such a group ext3_trim_all_free function is +* invoked to trim all free space. +*/ +int ext3_trim_fs (unsigned int minlen,struct super_block *sb) +{ +ext3_grpblk_t minblocks; +unsigned long ngroups; +unsigned int group; +struct ext3_group_desc *gdp; +ext3_grpblk_t free_blocks; +int ret =0 ; + + minblocks =DIV_ROUND_UP (minlen, sb->s_blocksize); +if (unlikely (minblocks >EXT3_BLOCKS_PER_GROUP (sb))) +return -EINVAL ; + + ngroups =EXT3_SB (sb)->s_groups_count; +smp_rmb (); + +for (group =0 ; group < ngroups; group++) { + + gdp =ext3_get_group_desc (sb, group,NULL ); +if (!gdp) +break ; + + free_blocks =le16_to_cpu (gdp->bg_free_blocks_count); +if (free_blocks < minblocks) +continue ; + + ret =ext3_trim_all_free (sb, group, minblocks); +if (ret <0 ) +break ; + } + +if (ret >=0 ) + ret =0 ; + +return ret; +}
fs/ext3/super.c +1 -0
@@ -797,6 +797,7 @@ static const struct super_operations ext3_sops = { .quota_write = ext3_quota_write, #endif .bdev_try_to_free_page = bdev_try_to_free_page, + .trim_fs = ext3_trim_fs, }; static const struct export_operations ext3_export_ops = {
include/linux/ext3_fs.h +1 -0
@@ -857,6 +857,7 @@ extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,extern int ext3_should_retry_alloc (struct super_block *sb,int *retries);extern void ext3_init_block_alloc_info (struct inode *);extern void ext3_rsv_window_add (struct super_block *sb,struct ext3_reserve_window_node *rsv); +extern int ext3_trim_fs (unsigned int minlen,struct super_block *sb);/* dir.c */ extern int ext3_check_dir_entry(const char *, struct inode *,
Signature · 1 line
1.7.2
Jan Kara
reviewerRe: [PATCH 2/3] Add batched discard support for ext3
Hi,
The patch looks good. Just one small thing:
fs/ext3/balloc.c unsigned long ext3_bg_num_gdb(struct super_block *sb, int group) · line 1937
Quoted 5 lines · Lukas Czerner
fs/ext3/balloc.c +5
-0+ gdp =ext3_get_group_desc (sb, group, &gdp_bh); +if (!gdp) + goto err_out; + +BUFFER_TRACE (gd_bh,"get_write_access" );
^^^^^ gdp_bh
So you can add: Reviewed-by: Jan Kara <[email protected]>
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Re: [PATCH 2/3] Add batched discard support for ext3
Quoted 12 lines · Jan Kara
Hi,
The patch looks good. Just one small thing:
fs/ext3/balloc.c unsigned long ext3_bg_num_gdb(struct super_block *sb, int group) · line 1937
Quoted 5 lines · Lukas Czerner
fs/ext3/balloc.c +5
-0+ gdp =ext3_get_group_desc (sb, group, &gdp_bh); +if (!gdp) + goto err_out; + +BUFFER_TRACE (gd_bh,"get_write_access" );^^^^^ gdp_bh
Quoted 4 lines
So you can add: Reviewed-by: Jan Kara <[email protected]>
Honza
Hi,
thanks a lot for your review. I will resend both patches shortly.
Regards.
-Lukas
Re: [PATCH 2/3] Add batched discard support for ext3
In reply to Lukas CzernerQuoted 11 lines · Lukas Czerner
fs/ext3/balloc.c +11
-0+/* +* Clear bits in the bitmap +*/ +for (bit = start; bit < next; bit++) { +BUFFER_TRACE (bitmap_bh,"clear bit" ); +if (!ext3_clear_bit_atomic (sb_bgl_lock (sbi, group), + bit, bitmap_bh->b_data)) { +ext3_error (sb, __func__, +"bit already cleared for block " E3FSBLK , + (unsigned long )bit); +BUFFER_TRACE (bitmap_bh,"bit already cleared" );
fs/ext3/balloc.c unsigned long ext3_bg_num_gdb(struct super_block *sb, int group) · line 2008
Quoted 10 lines
fs/ext3/balloc.c +10
-0+ }else { + freed++; + } + } + +/* Update couters */ +spin_lock (sb_bgl_lock (sbi, group)); +le16_add_cpu (&gdp->bg_free_blocks_count, freed); +spin_unlock (sb_bgl_lock (sbi, group)); +percpu_counter_add (&sbi->s_freeblocks_counter, next - start);
It wouldn't be a terrible idea to put this code into a helper function that is shared with ext3_free_blocks_sb() so that it is kept in sync. There are a lot of places that need to be kept coordinated (disk bitmap, memory bitmap, group descriptor, percpu counter) so I'd like that to be localized to one part of the code.
Cheers, Andreas
Re: [PATCH 2/3] Add batched discard support for ext3
Quoted 26 lines · Andreas Dilger
Quoted 11 lines · Lukas Czerner
fs/ext3/balloc.c +11
-0+/* +* Clear bits in the bitmap +*/ +for (bit = start; bit < next; bit++) { +BUFFER_TRACE (bitmap_bh,"clear bit" ); +if (!ext3_clear_bit_atomic (sb_bgl_lock (sbi, group), + bit, bitmap_bh->b_data)) { +ext3_error (sb, __func__, +"bit already cleared for block " E3FSBLK , + (unsigned long )bit); +BUFFER_TRACE (bitmap_bh,"bit already cleared" );fs/ext3/balloc.c unsigned long ext3_bg_num_gdb(struct super_block *sb, int group) · line 2008
Quoted 10 lines
fs/ext3/balloc.c +10
-0+ }else { + freed++; + } + } + +/* Update couters */ +spin_lock (sb_bgl_lock (sbi, group)); +le16_add_cpu (&gdp->bg_free_blocks_count, freed); +spin_unlock (sb_bgl_lock (sbi, group)); +percpu_counter_add (&sbi->s_freeblocks_counter, next - start);It wouldn't be a terrible idea to put this code into a helper function that is shared with
ext3_free_blocks_sb()so that it is kept in sync. There are a lot of places that need to be kept coordinated (disk bitmap, memory bitmap, group descriptor, percpu counter) so I'd like that to be localized to one part of the code.
Quoted 2 lines
Cheers, Andreas
Ok, I will see what I can do with that.
Thanks.
-Lukas
PATCH 3/3 Add batched discard support for ext4
In reply to Lukas CzernerWalk through each allocation group and trim all free extents. It can be invoked through TRIM ioctl on the file system. The main idea is to provide a way to trim the whole file system if needed, since some SSD's may suffer from performance loss after the whole device was filled (it does not mean that fs is full!).
It search fro free extents in each allocation group. When the free extent is found, blocks are marked as used in the buddy bitmap and then trimmed. Afterwards these blocks are marked as free in per-group buddy bitmap.
Since fstrim is a long operation it is good to have an ability to interrupt it by a signal. This was added by Dmitry Monakhov. Thanks Dimitry.
--- fs/ext4/ext4.h | 2 + fs/ext4/mballoc.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/super.c | 1 + 3 files changed, 160 insertions(+), 0 deletions(-)
fs/ext4/ext4.h +2 -0
@@ -1558,6 +1558,8 @@ extern int ext4_mb_add_groupinfo(struct super_block *sb,extern int ext4_mb_get_buddy_cache_lock (struct super_block *,ext4_group_t );extern void ext4_mb_put_buddy_cache_lock (struct super_block *,ext4_group_t ,int ); +extern int ext4_trim_fs (unsigned int ,struct super_block *); +/* inode.c */ struct buffer_head *ext4_getblk (handle_t *,struct inode *,ext4_lblk_t ,int ,int *);
fs/ext4/mballoc.c +157 -0
160 lines not on this page · raw message
fs/ext4/super.c +1 -0
@@ -1114,6 +1114,7 @@ static const struct super_operations ext4_sops = { .quota_write = ext4_quota_write, #endif .bdev_try_to_free_page = bdev_try_to_free_page, + .trim_fs = ext4_trim_fs }; static const struct super_operations ext4_nojournal_sops = {
Signature · 1 line
1.7.2
Jan Kara
reviewerRe: [PATCH 3/3] Add batched discard support for ext4
Quoted 11 lines · Lukas Czerner
Walk through each allocation group and trim all free extents. It can be invoked through TRIM ioctl on the file system. The main idea is to provide a way to trim the whole file system if needed, since some SSD's may suffer from performance loss after the whole device was filled (it does not mean that fs is full!).
It search fro free extents in each allocation group. When the free extent is found, blocks are marked as used in the buddy bitmap and then trimmed. Afterwards these blocks are marked as free in per-group buddy bitmap.
Quoted 5 lines
Since fstrim is a long operation it is good to have an ability to interrupt it by a signal. This was added by Dmitry Monakhov. Thanks Dimitry.
Signed-off-by Lukas Czerner <[email protected]>Signed-off-by Dmitry Monakhov <[email protected]>
This patch looks OK as well. Just one question:
fs/ext4/mballoc.c error_return: · line 4735
Quoted 2 lines
fs/ext4/mballoc.c +2
-0+ ret =sb_issue_discard (sb, discard_block, count); +if (ret ==EOPNOTSUPP ) {
^^ Here should be -EOPNOTSUPP, or generally a check
that ret < 0 would be better as -EIO or so can be returned as well. The same comment actually applies for the ext3 patch.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 14 lines · Lukas Czerner
Adds an filesystem independent ioctl to allow implementation of file system batched discard support.
Signed-off-by Lukas Czerner <[email protected]>--- fs/ioctl.c | 31 +++++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 33 insertions(+), 0 deletions(-)fs/ioctl.c +0
-0
fs/ioctl.c static int ioctl_fsthaw(struct file *filp) · line 543
Quoted 4 lines
fs/ioctl.c +1
-0@@ -540,6 +540,33 @@ static int ioctl_fsthaw(struct file *filp)return thaw_super (sb); } +static int ioctl_fstrim (struct file *filp,unsigned long arg)
BTW why do we have to trim fs in one shot ?
IMHO it is much suitable to provide start,len parameters as we do in most functions(truncate, bdevdiscard, getdents).
It allow userspace caller to implement a fancy looking progress bars.
Quoted 60 lines
fs/ioctl.c +30
-0+{ +struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; +unsigned int minlen; +int err; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +/* If filesystem doesn't support trim feature, return. */ +if (sb->s_op->trim_fs ==NULL ) +return -EOPNOTSUPP ; + +/* If a blockdevice-backed filesystem isn't specified, return EINVAL. */ +if (sb->s_bdev ==NULL ) +return -EINVAL ; + + err =get_user (minlen, (unsigned int __user *) arg); +if (err) +return err; + + err = sb->s_op->trim_fs (minlen, sb); +if (err) +return err; +return 0 ; +} +/* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too. @@ -590,6 +617,10 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, error =ioctl_fsthaw (filp);break ; +case FITRIM : + error =ioctl_fstrim (filp, arg); +break ; +case FS_IOC_FIEMAP :return ioctl_fiemap (filp, arg);include/linux/fs.h +2
-0@@ -315,6 +315,7 @@ struct inodes_stat_t {#define FIGETBSZ _IO(0x00,2)/* get the block size used for bmap */ #define FIFREEZE _IOWR('X', 119, int)/* Freeze */ #define FITHAW _IOWR('X', 120, int)/* Thaw */ +#define FITRIM _IOWR('X', 121, int)/* Trim */ #define FS_IOC_GETFLAGS _IOR('f', 1, long)#define FS_IOC_SETFLAGS _IOW('f', 2, long)@@ -1580,6 +1581,7 @@ struct super_operations {ssize_t (*quota_write)(struct super_block *,int ,const char *,size_t ,loff_t );#endif int (*bdev_try_to_free_page)(struct super_block *,struct page *,gfp_t ); +int (*trim_fs) (unsigned int ,struct super_block *); };/*
Quoted 19 lines · Dmitry Monakhov
Quoted 17 lines · Lukas Czerner
Adds an filesystem independent ioctl to allow implementation of file system batched discard support.
Signed-off-by Lukas Czerner <[email protected]>--- fs/ioctl.c | 31 +++++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 33 insertions(+), 0 deletions(-)fs/ioctl.c +0
-0@@ -540,6 +540,33 @@ static int ioctl_fsthaw(struct file *filp)return thaw_super (sb); }
Quoted 5 lines
fs/ioctl.c static int ioctl_fsthaw(struct file *filp) · line 543
Quoted 1 line
fs/ioctl.c +1
-0+static int ioctl_fstrim (struct file *filp,unsigned long arg)BTW why do we have to trim fs in one shot ?
IMHO it is much suitable to provide start,len parameters as we do in mostfunctions(truncate, bdevdiscard, getdents).
It allow userspace caller to implement a fancy looking progress bars.
Hi,
do you think it is really needed when even with todays SSD's it takes just a couple of seconds ? And I suppose it will improve in future. But generally I think we can do that..I would like to hear some more opinions before I start looking at this.
Thanks.
-Lukas.
Quoted 65 lines
Quoted 53 lines
fs/ioctl.c +30
-0+{ +struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; +unsigned int minlen; +int err; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +/* If filesystem doesn't support trim feature, return. */ +if (sb->s_op->trim_fs ==NULL ) +return -EOPNOTSUPP ; + +/* If a blockdevice-backed filesystem isn't specified, return EINVAL. */ +if (sb->s_bdev ==NULL ) +return -EINVAL ; + + err =get_user (minlen, (unsigned int __user *) arg); +if (err) +return err; + + err = sb->s_op->trim_fs (minlen, sb); +if (err) +return err; +return 0 ; +} +/* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too. @@ -590,6 +617,10 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, error =ioctl_fsthaw (filp);break ; +case FITRIM : + error =ioctl_fstrim (filp, arg); +break ; +case FS_IOC_FIEMAP :return ioctl_fiemap (filp, arg);include/linux/fs.h +1
-0@@ -315,6 +315,7 @@ struct inodes_stat_t {#define FIGETBSZ _IO(0x00,2)/* get the block size used for bmap */ #define FIFREEZE _IOWR('X', 119, int)/* Freeze */ #define FITHAW _IOWR('X', 120, int)/* Thaw */ +#define FITRIM _IOWR('X', 121, int)/* Trim */ #define FS_IOC_GETFLAGS _IOR('f', 1, long)#define FS_IOC_SETFLAGS _IOW('f', 2, long)include/linux/fs.h struct super_operations { · line 1587
Quoted 7 lines
include/linux/fs.h +1
-0@@ -1580,6 +1581,7 @@ struct super_operations {ssize_t (*quota_write)(struct super_block *,int ,const char *,size_t ,loff_t );#endif int (*bdev_try_to_free_page)(struct super_block *,struct page *,gfp_t ); +int (*trim_fs) (unsigned int ,struct super_block *); };/* --
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 29 lines · Lukas Czerner
Quoted 19 lines · Dmitry Monakhov
Quoted 17 lines · Lukas Czerner
Adds an filesystem independent ioctl to allow implementation of file system batched discard support.
Signed-off-by Lukas Czerner <[email protected]>---
fs/ioctl.c | 31 +++++++++++++++++++++++++++++++include/linux/fs.h| 2 ++2 files changed, 33 insertions(+), 0 deletions(-)fs/ioctl.c +0
-0@@ -540,6 +540,33 @@ static int ioctl_fsthaw(struct file *filp) return thaw_super(sb); }Quoted 5 lines
fs/ioctl.c static int ioctl_fsthaw(struct file *filp) · line 543
Quoted 1 line
fs/ioctl.c +1
-0+static int ioctl_fstrim (struct file *filp,unsigned long arg)BTW why do we have to trim fs in one shot ?
IMHO it is much suitable to provide start,len parameters as we do in mostfunctions(truncate, bdevdiscard, getdents).
It allow userspace caller to implement a fancy looking progress bars.Hi,
Quoted 8 lines
do you think it is really needed when even with todays SSD's it takes just a couple of seconds ? And I suppose it will improve in future. But generally I think we can do that..I would like to hear some more opinions before I start looking at this.
Thanks.
-Lukas.
Since the proposed patch is not aggregating discards into multiple ranges per ATA command, I thought some of the non-optimized devices would take minutes / hours?
If true, a way to control the progress from userspace is important.
If in general it is only going to take a few seconds for a full FITRIM to run, it is much less important, but I suppose the the RT project might find even that problematic.
Greg
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Ted Ts'o
maintainerQuoted 10 lines · Greg Freemyer
Since the proposed patch is not aggregating discards into multiple ranges per ATA command, I thought some of the non-optimized devices would take minutes / hours?
If true, a way to control the progress from userspace is important.
If in general it is only going to take a few seconds for a full FITRIM to run, it is much less important, but I suppose the the RT project might find even that problematic.
Even if it without the RT project, if disk activity is slowed or completely stopped for a few seconds, I can think of plenty of workloads where this would be totally unacceptable. Suppose you are running a web site; it doesn't really matter whether it is at Google, Facebook, Twitter, etc. If this means that one or more web pages get stalled by "a few seconds" while the FITRIM is going on, this is generally not considered acceptable. Even if it slows down the server by 30-50%, for some sites this would also be quite unacceptable.
This is a hard problem to solve, though, especially if there is an insistence to solve it in a fs-independent fashion. I could imagine doing this at work, by doing things one block group at a time, and then I could measure, for our specific hardware, how badly disk performance would get hit, and for how long, and then the userspace daemon could control how many block groups to do per unit time. But this would be of necessity ext2/3/4 specific....
So I'm not sure what to suggest here. Maybe the answer is we can have a fs-independent ioctl for desktop workloads, and one which gives more fine-grained control for those who need it? That seems ugly, but it might be the best compromise.
- Ted
Quoted 11 lines · Ted Ts'o
Quoted 10 lines · Greg Freemyer
Since the proposed patch is not aggregating discards into multiple ranges per ATA command, I thought some of the non-optimized devices would take minutes / hours?
If true, a way to control the progress from userspace is important.
If in general it is only going to take a few seconds for a full FITRIM to run, it is much less important, but I suppose the the RT project might find even that problematic.
Few second may not being true, We always have to think about crazy user, and crazy fs-layouts.
My SSD is able to process 8*10^3 requests per second
So in worst case( where 1k fs block are bysy like this 010101010101) it can process about 10^3/s * 2*1Kb = 16Mb/s
Which is no good.
Quoted 18 lines
Even if it without the RT project, if disk activity is slowed or completely stopped for a few seconds, I can think of plenty of workloads where this would be totally unacceptable. Suppose you are running a web site; it doesn't really matter whether it is at Google, Facebook, Twitter, etc. If this means that one or more web pages get stalled by "a few seconds" while the FITRIM is going on, this is generally not considered acceptable. Even if it slows down the server by 30-50%, for some sites this would also be quite unacceptable.
This is a hard problem to solve, though, especially if there is an insistence to solve it in a fs-independent fashion. I could imagine doing this at work, by doing things one block group at a time, and then I could measure, for our specific hardware, how badly disk performance would get hit, and for how long, and then the userspace daemon could control how many block groups to do per unit time. But this would be of necessity ext2/3/4 specific....
Quoted 4 lines
So I'm not sure what to suggest here. Maybe the answer is we can have a fs-independent ioctl for desktop workloads, and one which gives more fine-grained control for those who need it? That seems ugly, but it might be the best compromise.
Why do we have to invent a wheel again?
We already have BLKDISCARD which has following arguments:uint64_t range[2]
So IMHO it is reasonable that FITRIM should have following arguments uint64_t start, uint64_t len, uint64_t minlen.
No problems with compat, no problems with interactivity. User who does not care about interactivity may just call ioctl(fd, FITRIM, 0, LLONG_MAX, 0),
Quoted 6 lines
- Ted
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 16 lines · Ted Ts'o
Quoted 5 lines · Greg Freemyer
If true, a way to control the progress from userspace is important.
If in general it is only going to take a few seconds for a full FITRIM to run, it is much less important, but I suppose the the RT project might find even that problematic.
Even if it without the RT project, if disk activity is slowed or completely stopped for a few seconds, I can think of plenty of workloads where this would be totally unacceptable. Suppose you are running a web site; it doesn't really matter whether it is at Google, Facebook, Twitter, etc. If this means that one or more web pages get stalled by "a few seconds" while the FITRIM is going on, this is generally not considered acceptable. Even if it slows down the server by 30-50%, for some sites this would also be quite unacceptable.
Quoted 7 lines
This is a hard problem to solve, though, especially if there is an insistence to solve it in a fs-independent fashion. I could imagine doing this at work, by doing things one block group at a time, and then I could measure, for our specific hardware, how badly disk performance would get hit, and for how long, and then the userspace daemon could control how many block groups to do per unit time. But this would be of necessity ext2/3/4 specific....
I think "blockgroup at a time" is simply the extN way of "range of blocks at a time". Having an API that is requesting "trim free blocks from [M,N]" is a generic enough interface to apply to any filesystem. If there is some way to query the "efficient trim increment size" (i.e. block group for extN, allocation group for xfs, ??? for btrfs) then userspace could do it that way, or simply pick some fraction of the filesystem and use a nice power-of-two value and hope it works out.
Quoted 4 lines
So I'm not sure what to suggest here. Maybe the answer is we can have a fs-independent ioctl for desktop workloads, and one which gives more fine-grained control for those who need it? That seems ugly, but it might be the best compromise.
No, too ugly.
Cheers, Andreas
Quoted 27 lines · Lukas Czerner
Quoted 19 lines · Dmitry Monakhov
Quoted 17 lines · Lukas Czerner
Adds an filesystem independent ioctl to allow implementation of file system batched discard support.
Signed-off-by Lukas Czerner <[email protected]>--- fs/ioctl.c | 31 +++++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 33 insertions(+), 0 deletions(-)fs/ioctl.c +0
-0@@ -540,6 +540,33 @@ static int ioctl_fsthaw(struct file *filp)return thaw_super (sb); }Quoted 5 lines
fs/ioctl.c static int ioctl_fsthaw(struct file *filp) · line 543
Quoted 1 line
fs/ioctl.c +1
-0+static int ioctl_fstrim (struct file *filp,unsigned long arg)BTW why do we have to trim fs in one shot ?
IMHO it is much suitable to provide start,len parameters as we do in mostfunctions(truncate, bdevdiscard, getdents).
It allow userspace caller to implement a fancy looking progress bars.
Quoted 6 lines
Hi,
do you think it is really needed when even with todays SSD's it takes just a couple of seconds ? And I suppose it will improve in future. But generally I think we can do that..I would like to hear some more opinions before I start looking at this.
Hi, Lukas
we may face a really long delays due to bad layouts and slow devices Please read my response to Ted
I'm agree with you what this interface is important, BTW i already enabled FITRIM support on my notebook, my speed difference is about 2-3%. But let's provide right user interface from very beginning.
Quoted 74 lines
Thanks.
-Lukas.
Quoted 59 lines
Quoted 59 lines
fs/ioctl.c +30
-0+{ +struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; +unsigned int minlen; +int err; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +/* If filesystem doesn't support trim feature, return. */ +if (sb->s_op->trim_fs ==NULL ) +return -EOPNOTSUPP ; + +/* If a blockdevice-backed filesystem isn't specified, return EINVAL. */ +if (sb->s_bdev ==NULL ) +return -EINVAL ; + + err =get_user (minlen, (unsigned int __user *) arg); +if (err) +return err; + + err = sb->s_op->trim_fs (minlen, sb); +if (err) +return err; +return 0 ; +} +/* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too. @@ -590,6 +617,10 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, error =ioctl_fsthaw (filp);break ; +case FITRIM : + error =ioctl_fstrim (filp, arg); +break ; +case FS_IOC_FIEMAP :return ioctl_fiemap (filp, arg);include/linux/fs.h +2
-0@@ -315,6 +315,7 @@ struct inodes_stat_t {#define FIGETBSZ _IO(0x00,2)/* get the block size used for bmap */ #define FIFREEZE _IOWR('X', 119, int)/* Freeze */ #define FITHAW _IOWR('X', 120, int)/* Thaw */ +#define FITRIM _IOWR('X', 121, int)/* Trim */ #define FS_IOC_GETFLAGS _IOR('f', 1, long)#define FS_IOC_SETFLAGS _IOW('f', 2, long)@@ -1580,6 +1581,7 @@ struct super_operations {ssize_t (*quota_write)(struct super_block *,int ,const char *,size_t ,loff_t );#endif int (*bdev_try_to_free_page)(struct super_block *,struct page *,gfp_t ); +int (*trim_fs) (unsigned int ,struct super_block *); };Quoted 6 lines
include/linux/fs.h struct super_operations { · line 1587
Quoted 1 line
include/linux/fs.h +0
-0/* --
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 35 lines · Dmitry Monakhov
Quoted 27 lines · Lukas Czerner
Quoted 19 lines · Dmitry Monakhov
Quoted 17 lines · Lukas Czerner
Adds an filesystem independent ioctl to allow implementation of file system batched discard support.
Signed-off-by Lukas Czerner <[email protected]>--- fs/ioctl.c | 31 +++++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 33 insertions(+), 0 deletions(-)fs/ioctl.c +0
-0@@ -540,6 +540,33 @@ static int ioctl_fsthaw(struct file *filp)return thaw_super (sb); }Quoted 5 lines
fs/ioctl.c static int ioctl_fsthaw(struct file *filp) · line 543
Quoted 1 line
fs/ioctl.c +1
-0+static int ioctl_fstrim (struct file *filp,unsigned long arg)BTW why do we have to trim fs in one shot ?
IMHO it is much suitable to provide start,len parameters as we do in mostfunctions(truncate, bdevdiscard, getdents).
It allow userspace caller to implement a fancy looking progress bars.Quoted 6 lines
Hi,
do you think it is really needed when even with todays SSD's it takes just a couple of seconds ? And I suppose it will improve in future. But generally I think we can do that..I would like to hear some more opinions before I start looking at this.
Quoted 6 lines
Hi, Lukas
we may face a really long delays due to bad layouts and slow devices Please read my response to Ted
I'm agree with you what this interface is important, BTW i already enabled FITRIM support on my notebook, my speed difference is about 2-3%. But let's provide right user interface from very beginning.
Hi, Dimitry
I read the thread and really it makes sense to me. Sometimes it can be useful to have more fine-grained control beside just specifying minlen argument, which works quite well, however it is a little bit fuzzy because when you do not know how much space was actually trimmed.
I think that there is no need to have two separate ioctls, even though it would be more effective to specify block group instead of block range. I am thinking about something like int optimize which will tell us to round the range to block group boundaries. But I can not tell if it would really help someone (probably not).
So I will try to do something to be able to break the FITRIM to smaller pieces, uint64_t start, uint64_t len, uint64_t minlen seems good to me.
Thanks
-Lukas