[RFC,01/11] fs: common implementation of file type conversions
diff mbox

Message ID 1482178268-22883-2-git-send-email-amir73il@gmail.com
State New
Headers show

Commit Message

Amir Goldstein Dec. 19, 2016, 8:10 p.m. UTC
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@gmail.com>
---
 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

Comments

Darrick J. Wong Dec. 19, 2016, 9:13 p.m. UTC | #1
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@gmail.com>
> ---
>  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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Amir Goldstein Dec. 20, 2016, 5:01 a.m. UTC | #2
On Mon, Dec 19, 2016 at 11:13 PM, Darrick J. Wong
<darrick.wong@oracle.com> 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@gmail.com>
>> ---
>>  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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

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,
+	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