On Mon, Dec 19, 2016 at 11:13 PM, Darrick J. Wong <darrick.wong@xxxxxxxxxx> wrote: > On Mon, Dec 19, 2016 at 10:10:58PM +0200, Amir Goldstein wrote: >> Many file systems use a copy&paste implementation >> of dirent to on-disk file type conversions. >> >> Create a common implementation to be used by file systems >> with some useful conversion helpers to reduce open coded >> file type conversions in file system code. >> >> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> >> --- >> include/linux/file_type.h | 107 ++++++++++++++++++++++++++++++++++++++++++++++ >> include/linux/fs.h | 17 +------- >> 2 files changed, 108 insertions(+), 16 deletions(-) >> create mode 100644 include/linux/file_type.h >> >> diff --git a/include/linux/file_type.h b/include/linux/file_type.h >> new file mode 100644 >> index 0000000..03ee1a1 >> --- /dev/null >> +++ b/include/linux/file_type.h >> @@ -0,0 +1,107 @@ >> +#ifndef _LINUX_FILE_TYPE_H >> +#define _LINUX_FILE_TYPE_H >> + >> +/* >> + * This is a common implementation of dirent to fs on-disk >> + * file type conversion. Although the fs on-disk bits are >> + * specific to every file system, in practice, many file systems >> + * use the exact same on-disk format to describe the lower 3 >> + * file type bits that represent the 7 POSIX file types. >> + * All those file systems can use this generic code for the >> + * conversions: >> + * i_mode -> fs on-disk file type (ftype) >> + * fs on-disk file type (ftype) -> dirent file type (dtype) >> + * i_mode -> dirent file type (dtype) >> + */ >> + >> +/* >> + * struct dirent file types >> + * exposed to user via getdents(2), readdir(3) >> + * >> + * These match bits 12..15 of stat.st_mode >> + * (ie "(i_mode >> 12) & 15"). >> + */ >> +#define S_DT_SHIFT 12 >> +#define S_DT(mode) (((mode) & S_IFMT) >> S_DT_SHIFT) >> +#define DT_MASK (S_IFMT >> S_DT_SHIFT) >> + >> +#define DT_UNKNOWN 0 >> +#define DT_FIFO S_DT(S_IFIFO) /* 1 */ >> +#define DT_CHR S_DT(S_IFCHR) /* 2 */ >> +#define DT_DIR S_DT(S_IFDIR) /* 4 */ >> +#define DT_BLK S_DT(S_IFBLK) /* 6 */ >> +#define DT_REG S_DT(S_IFREG) /* 8 */ >> +#define DT_LNK S_DT(S_IFLNK) /* 10 */ >> +#define DT_SOCK S_DT(S_IFSOCK) /* 12 */ >> +#define DT_WHT 14 >> + >> +#define DT_MAX (DT_MASK + 1) /* 16 */ >> + >> +/* >> + * fs on-disk file types. >> + * Only the low 3 bits are used for the POSIX file types. >> + * Other bits are reserved for fs private use. >> + * >> + * Note that no fs currently stores the whiteout type on-disk, >> + * so whiteout dirents are exposed to user as DT_CHR. >> + */ >> +#define FT_UNKNOWN 0 >> +#define FT_REG_FILE 1 >> +#define FT_DIR 2 >> +#define FT_CHRDEV 3 >> +#define FT_BLKDEV 4 >> +#define FT_FIFO 5 >> +#define FT_SOCK 6 >> +#define FT_SYMLINK 7 >> + >> +#define FT_MAX 8 >> + >> +/* >> + * fs on-disk file type to dirent file type conversion >> + */ >> +static unsigned char fs_dtype_by_ftype[] = { >> + DT_UNKNOWN, > > [FT_UNKNOWN] = DT_UNKNOWN, etc? > sure. > It's not strictly necessary but it makes the mapping more explicit. > > --D > >> + DT_REG, >> + DT_DIR, >> + DT_CHR, >> + DT_BLK, >> + DT_FIFO, >> + DT_SOCK, >> + DT_LNK >> +}; >> + >> +static inline unsigned char fs_dtype(int filetype) >> +{ >> + if (filetype >= FT_MAX) >> + return DT_UNKNOWN; >> + >> + return fs_dtype_by_ftype[filetype]; >> +} >> + >> +/* >> + * dirent file type to fs on-disk file type conversion >> + * Values not initialized explicitly are FT_UNKNOWN (0). >> + */ >> +static unsigned char fs_ftype_by_dtype[DT_MAX] = { >> + [DT_REG] = FT_REG_FILE, >> + [DT_DIR] = FT_DIR, >> + [DT_LNK] = FT_SYMLINK, >> + [DT_CHR] = FT_CHRDEV, >> + [DT_BLK] = FT_BLKDEV, >> + [DT_FIFO] = FT_FIFO, >> + [DT_SOCK] = FT_SOCK, >> +}; >> + >> +/* st_mode to fs on-disk file type conversion */ >> +static inline unsigned char fs_umode_to_ftype(umode_t mode) >> +{ >> + return fs_ftype_by_dtype[S_DT(mode)]; >> +} >> + >> +/* st_mode to dirent file type conversion */ >> +static inline unsigned char fs_umode_to_dtype(umode_t mode) >> +{ >> + return fs_dtype(fs_umode_to_ftype(mode)); >> +} >> + >> +#endif >> diff --git a/include/linux/fs.h b/include/linux/fs.h >> index e6e4146..8f1580d 100644 >> --- a/include/linux/fs.h >> +++ b/include/linux/fs.h >> @@ -31,6 +31,7 @@ >> #include <linux/workqueue.h> >> #include <linux/percpu-rwsem.h> >> #include <linux/delayed_call.h> >> +#include <linux/file_type.h> >> >> #include <asm/byteorder.h> >> #include <uapi/linux/fs.h> >> @@ -1582,22 +1583,6 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical, >> int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); >> >> /* >> - * File types >> - * >> - * NOTE! These match bits 12..15 of stat.st_mode >> - * (ie "(i_mode >> 12) & 15"). >> - */ >> -#define DT_UNKNOWN 0 >> -#define DT_FIFO 1 >> -#define DT_CHR 2 >> -#define DT_DIR 4 >> -#define DT_BLK 6 >> -#define DT_REG 8 >> -#define DT_LNK 10 >> -#define DT_SOCK 12 >> -#define DT_WHT 14 >> - >> -/* >> * This is the "filldir" function type, used by readdir() to let >> * the kernel specify what kind of dirent layout it wants to have. >> * This allows the kernel to read directories into kernel space or >> -- >> 2.7.4 >> -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html