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? 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