ext2: use common file type conversion
RFC PATCH v2 4/10 ext2: use common file type conversion
Deduplicate the ext2 file type conversion implementation.
Original patch by Amir Goldstein.
v2:
- Rebased against Linux 4.19 by Phillip Potter
- This version does not remove EXT2_FT_x enum from fs/ext2/ext2.h, as these values are now used in compile-time checks added by Phillip Potter to make sure they remain the same as FT_x values
v1:
- Initial implementation
--- fs/ext2/dir.c | 51 ++++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 29 deletions(-)
fs/ext2/dir.c +22 -29
@@ -252,33 +252,10 @@ ext2_validate_entry(char *base, unsigned offset, unsigned mask)return (char *)p - base; } -static unsigned char ext2_filetype_table[EXT2_FT_MAX ] = { - [EXT2_FT_UNKNOWN ] =DT_UNKNOWN , - [EXT2_FT_REG_FILE ] =DT_REG , - [EXT2_FT_DIR ] =DT_DIR , - [EXT2_FT_CHRDEV ] =DT_CHR , - [EXT2_FT_BLKDEV ] =DT_BLK , - [EXT2_FT_FIFO ] =DT_FIFO , - [EXT2_FT_SOCK ] =DT_SOCK , - [EXT2_FT_SYMLINK ] =DT_LNK , -}; - -#define S_SHIFT 12 -static unsigned char ext2_type_by_mode[S_IFMT >>S_SHIFT ] = { - [S_IFREG >>S_SHIFT ] =EXT2_FT_REG_FILE , - [S_IFDIR >>S_SHIFT ] =EXT2_FT_DIR , - [S_IFCHR >>S_SHIFT ] =EXT2_FT_CHRDEV , - [S_IFBLK >>S_SHIFT ] =EXT2_FT_BLKDEV , - [S_IFIFO >>S_SHIFT ] =EXT2_FT_FIFO , - [S_IFSOCK >>S_SHIFT ] =EXT2_FT_SOCK , - [S_IFLNK >>S_SHIFT ] =EXT2_FT_SYMLINK , -}; -static inline void ext2_set_de_type (ext2_dirent *de,struct inode *inode) { -umode_t mode = inode->i_mode;if (EXT2_HAS_INCOMPAT_FEATURE (inode->i_sb,EXT2_FEATURE_INCOMPAT_FILETYPE )) - de->file_type = ext2_type_by_mode[(mode &S_IFMT )>>S_SHIFT ]; + de->file_type =fs_umode_to_ftype (inode->i_mode);else de->file_type =0 ; }
@@ -293,14 +270,14 @@ ext2_readdir(struct file *file, struct dir_context *ctx)unsigned long n = pos >>PAGE_SHIFT ;unsigned long npages =dir_pages (inode);unsigned chunk_mask = ~(ext2_chunk_size (inode)-1 ); -unsigned char *types =NULL ;bool need_revalidate = !inode_eq_iversion (inode, file->f_version); +bool has_filetype;if (pos > inode->i_size -EXT2_DIR_REC_LEN (1 ))return 0 ; -if (EXT2_HAS_INCOMPAT_FEATURE (sb,EXT2_FEATURE_INCOMPAT_FILETYPE )) - types = ext2_filetype_table; + has_filetype = +EXT2_HAS_INCOMPAT_FEATURE (sb,EXT2_FEATURE_INCOMPAT_FILETYPE );for ( ; n < npages; n++, offset =0 ) {char *kaddr, *limit;
@@ -335,8 +312,24 @@ ext2_readdir(struct file *file, struct dir_context *ctx) if (de->inode) { unsigned char d_type = DT_UNKNOWN; - if (types && de->file_type < EXT2_FT_MAX) - d_type = types[de->file_type]; + /* + * compile-time asserts that generic FT_x types + * still match EXT2_FT_x types - no need to list + * for other functions as well as build will + * fail either way + */ + BUILD_BUG_ON(EXT2_FT_UNKNOWN != FT_UNKNOWN); + BUILD_BUG_ON(EXT2_FT_REG_FILE != FT_REG_FILE); + BUILD_BUG_ON(EXT2_FT_DIR != FT_DIR); + BUILD_BUG_ON(EXT2_FT_CHRDEV != FT_CHRDEV); + BUILD_BUG_ON(EXT2_FT_BLKDEV != FT_BLKDEV); + BUILD_BUG_ON(EXT2_FT_FIFO != FT_FIFO); + BUILD_BUG_ON(EXT2_FT_SOCK != FT_SOCK); + BUILD_BUG_ON(EXT2_FT_SYMLINK != FT_SYMLINK); + BUILD_BUG_ON(EXT2_FT_MAX != FT_MAX); + + if (has_filetype) + d_type = fs_dtype(de->file_type); if (!dir_emit(ctx, de->name, de->name_len, le32_to_cpu(de->inode),
Signature · 1 line
2.17.2
Quoted 5 lines · Phillip Potter
Deduplicate the ext2 file type conversion implementation.
Original patch by Amir Goldstein.
Quoted 9 lines
v2:
- Rebased against Linux 4.19 by Phillip Potter
- This version does not removeEXT2_FT_xenum fromfs/ext2/ext2.h, as these values are now used in compile-time checks added by Phillip Potter to make sure they remain the same asFT_xvaluesv1:
- Initial implementation
Same comments as how to apply a patch and about changelog as patch 1. Won't repeat for other patches.
I think it would be also good to mention there is a lurking bug if code ever tries to access ext2_type_by_mode[S_IFMT] because on-disk data is corrupted.
Quoted 73 lines
Signed-off-by Phillip Potter <[email protected]>--- fs/ext2/dir.c | 51 ++++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 29 deletions(-)fs/ext2/dir.c +9
-29@@ -252,33 +252,10 @@ ext2_validate_entry(char *base, unsigned offset, unsigned mask)return (char *)p - base; } -static unsigned char ext2_filetype_table[EXT2_FT_MAX ] = { - [EXT2_FT_UNKNOWN ] =DT_UNKNOWN , - [EXT2_FT_REG_FILE ] =DT_REG , - [EXT2_FT_DIR ] =DT_DIR , - [EXT2_FT_CHRDEV ] =DT_CHR , - [EXT2_FT_BLKDEV ] =DT_BLK , - [EXT2_FT_FIFO ] =DT_FIFO , - [EXT2_FT_SOCK ] =DT_SOCK , - [EXT2_FT_SYMLINK ] =DT_LNK , -}; - -#define S_SHIFT 12 -static unsigned char ext2_type_by_mode[S_IFMT >>S_SHIFT ] = { - [S_IFREG >>S_SHIFT ] =EXT2_FT_REG_FILE , - [S_IFDIR >>S_SHIFT ] =EXT2_FT_DIR , - [S_IFCHR >>S_SHIFT ] =EXT2_FT_CHRDEV , - [S_IFBLK >>S_SHIFT ] =EXT2_FT_BLKDEV , - [S_IFIFO >>S_SHIFT ] =EXT2_FT_FIFO , - [S_IFSOCK >>S_SHIFT ] =EXT2_FT_SOCK , - [S_IFLNK >>S_SHIFT ] =EXT2_FT_SYMLINK , -}; -static inline void ext2_set_de_type (ext2_dirent *de,struct inode *inode) { -umode_t mode = inode->i_mode;if (EXT2_HAS_INCOMPAT_FEATURE (inode->i_sb,EXT2_FEATURE_INCOMPAT_FILETYPE )) - de->file_type = ext2_type_by_mode[(mode &S_IFMT )>>S_SHIFT ]; + de->file_type =fs_umode_to_ftype (inode->i_mode);else de->file_type =0 ; }@@ -293,14 +270,14 @@ ext2_readdir(struct file *file, struct dir_context *ctx)unsigned long n = pos >>PAGE_SHIFT ;unsigned long npages =dir_pages (inode);unsigned chunk_mask = ~(ext2_chunk_size (inode)-1 ); -unsigned char *types =NULL ;bool need_revalidate = !inode_eq_iversion (inode, file->f_version); +bool has_filetype;if (pos > inode->i_size -EXT2_DIR_REC_LEN (1 ))return 0 ; -if (EXT2_HAS_INCOMPAT_FEATURE (sb,EXT2_FEATURE_INCOMPAT_FILETYPE )) - types = ext2_filetype_table; + has_filetype = +EXT2_HAS_INCOMPAT_FEATURE (sb,EXT2_FEATURE_INCOMPAT_FILETYPE );for ( ; n < npages; n++, offset =0 ) {char *kaddr, *limit;@@ -335,8 +312,24 @@ ext2_readdir(struct file *file, struct dir_context *ctx)if (de->inode) {unsigned char d_type =DT_UNKNOWN ; -if (types && de->file_type <EXT2_FT_MAX ) - d_type = types[de->file_type]; +/* +* compile-time asserts that generic FT_x types +* still match EXT2_FT_x types - no need to list +* for other functions as well as build will +* fail either way
fs/ext2/dir.c ext2_readdir(struct file *file, struct dir_context *ctx) · line 329
Quoted 10 lines
fs/ext2/dir.c +10
-0+*/ +BUILD_BUG_ON (EXT2_FT_UNKNOWN !=FT_UNKNOWN ); +BUILD_BUG_ON (EXT2_FT_REG_FILE !=FT_REG_FILE ); +BUILD_BUG_ON (EXT2_FT_DIR !=FT_DIR ); +BUILD_BUG_ON (EXT2_FT_CHRDEV !=FT_CHRDEV ); +BUILD_BUG_ON (EXT2_FT_BLKDEV !=FT_BLKDEV ); +BUILD_BUG_ON (EXT2_FT_FIFO !=FT_FIFO ); +BUILD_BUG_ON (EXT2_FT_SOCK !=FT_SOCK ); +BUILD_BUG_ON (EXT2_FT_SYMLINK !=FT_SYMLINK ); +BUILD_BUG_ON (EXT2_FT_MAX !=FT_MAX );
This bunch would look much nicer in ext2_set_de_type(). Always try to put those build time asserts near relevant code but also at the "beginning of something" in a place more pleasant to the eye.
Quoted 9 lines
fs/ext2/dir.c +3
-1+ +if (has_filetype) + d_type =fs_dtype (de->file_type); if (!dir_emit(ctx, de->name, de->name_len, le32_to_cpu(de->inode), --2.17.2
Quoted 17 lines · Amir Goldstein
Quoted 5 lines · Phillip Potter
Deduplicate the ext2 file type conversion implementation.
Original patch by Amir Goldstein.
Quoted 9 lines
v2:
- Rebased against Linux 4.19 by Phillip Potter
- This version does not removeEXT2_FT_xenum fromfs/ext2/ext2.h, as these values are now used in compile-time checks added by Phillip Potter to make sure they remain the same asFT_xvaluesv1:
- Initial implementation
Quoted 6 lines
Same comments as how to apply a patch and about changelog as patch 1. Won't repeat for other patches.
I think it would be also good to mention there is a lurking bug if code ever tries to access ext2_type_by_mode[S_IFMT] because on-disk data is corrupted.
So my old notes on the alleged ext2 bug:
https://marc.info/?l=linux-fsdevel&m=148243866204444&w=2
Quoted 67 lines
Quoted 67 lines
Signed-off-by Phillip Potter <[email protected]>--- fs/ext2/dir.c | 51 ++++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 29 deletions(-)fs/ext2/dir.c +4
-27@@ -252,33 +252,10 @@ ext2_validate_entry(char *base, unsigned offset, unsigned mask)return (char *)p - base; } -static unsigned char ext2_filetype_table[EXT2_FT_MAX ] = { - [EXT2_FT_UNKNOWN ] =DT_UNKNOWN , - [EXT2_FT_REG_FILE ] =DT_REG , - [EXT2_FT_DIR ] =DT_DIR , - [EXT2_FT_CHRDEV ] =DT_CHR , - [EXT2_FT_BLKDEV ] =DT_BLK , - [EXT2_FT_FIFO ] =DT_FIFO , - [EXT2_FT_SOCK ] =DT_SOCK , - [EXT2_FT_SYMLINK ] =DT_LNK , -}; - -#define S_SHIFT 12 -static unsigned char ext2_type_by_mode[S_IFMT >>S_SHIFT ] = { - [S_IFREG >>S_SHIFT ] =EXT2_FT_REG_FILE , - [S_IFDIR >>S_SHIFT ] =EXT2_FT_DIR , - [S_IFCHR >>S_SHIFT ] =EXT2_FT_CHRDEV , - [S_IFBLK >>S_SHIFT ] =EXT2_FT_BLKDEV , - [S_IFIFO >>S_SHIFT ] =EXT2_FT_FIFO , - [S_IFSOCK >>S_SHIFT ] =EXT2_FT_SOCK , - [S_IFLNK >>S_SHIFT ] =EXT2_FT_SYMLINK , -}; -static inline void ext2_set_de_type (ext2_dirent *de,struct inode *inode) { -umode_t mode = inode->i_mode;if (EXT2_HAS_INCOMPAT_FEATURE (inode->i_sb,EXT2_FEATURE_INCOMPAT_FILETYPE )) - de->file_type = ext2_type_by_mode[(mode &S_IFMT )>>S_SHIFT ]; + de->file_type =fs_umode_to_ftype (inode->i_mode);else de->file_type =0 ; }@@ -293,14 +270,14 @@ ext2_readdir(struct file *file, struct dir_context *ctx)unsigned long n = pos >>PAGE_SHIFT ;unsigned long npages =dir_pages (inode);unsigned chunk_mask = ~(ext2_chunk_size (inode)-1 ); -unsigned char *types =NULL ;bool need_revalidate = !inode_eq_iversion (inode, file->f_version); +bool has_filetype;if (pos > inode->i_size -EXT2_DIR_REC_LEN (1 ))return 0 ; -if (EXT2_HAS_INCOMPAT_FEATURE (sb,EXT2_FEATURE_INCOMPAT_FILETYPE )) - types = ext2_filetype_table; + has_filetype = +EXT2_HAS_INCOMPAT_FEATURE (sb,EXT2_FEATURE_INCOMPAT_FILETYPE );for ( ; n < npages; n++, offset =0 ) {char *kaddr, *limit;@@ -335,8 +312,24 @@ ext2_readdir(struct file *file, struct dir_context *ctx)if (de->inode) {unsigned char d_type =DT_UNKNOWN ;
Quoted 7 lines
fs/ext2/dir.c ext2_readdir(struct file *file, struct dir_context *ctx) · line 319
Quoted 7 lines
fs/ext2/dir.c +5
-2-if (types && de->file_type <EXT2_FT_MAX ) - d_type = types[de->file_type]; +/* +* compile-time asserts that generic FT_x types +* still match EXT2_FT_x types - no need to list +* for other functions as well as build will +* fail either way
Please remove the part about "no need to list for other functions..." Imagine how kernel code would look like if every call to BUILD_BUG_ON() would have a comment explaining how BUILD_BUG_ON() works...
Thanks,
Amir.