add f_flags to struct statfs(64)
Christoph Hellwig [Wed, 7 Jul 2010 16:53:25 +0000 (18:53 +0200)]
Add a flags field to help glibc implementing statvfs(3) efficiently.

We copy the flag values from glibc, and add a new ST_VALID flag to
denote that f_flags is implemented.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

arch/mips/include/asm/statfs.h
arch/s390/include/asm/statfs.h
fs/statfs.c
include/asm-generic/statfs.h
include/linux/statfs.h

index c3ddf97..0f805c7 100644 (file)
@@ -33,7 +33,8 @@ struct statfs {
        /* Linux specials */
        __kernel_fsid_t f_fsid;
        long            f_namelen;
-       long            f_spare[6];
+       long            f_flags;
+       long            f_spare[5];
 };
 
 #if (_MIPS_SIM == _MIPS_SIM_ABI32) || (_MIPS_SIM == _MIPS_SIM_NABI32)
@@ -53,7 +54,8 @@ struct statfs64 {
        __u64   f_bavail;
        __kernel_fsid_t f_fsid;
        __u32   f_namelen;
-       __u32   f_spare[6];
+       __u32   f_flags;
+       __u32   f_spare[5];
 };
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
@@ -73,7 +75,8 @@ struct statfs64 {                     /* Same as struct statfs */
        /* Linux specials */
        __kernel_fsid_t f_fsid;
        long            f_namelen;
-       long            f_spare[6];
+       long            f_flags;
+       long            f_spare[5];
 };
 
 struct compat_statfs64 {
@@ -88,7 +91,8 @@ struct compat_statfs64 {
        __u64   f_bavail;
        __kernel_fsid_t f_fsid;
        __u32   f_namelen;
-       __u32   f_spare[6];
+       __u32   f_flags;
+       __u32   f_spare[5];
 };
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
index 06cc703..3be7fbd 100644 (file)
@@ -33,7 +33,8 @@ struct statfs {
        __kernel_fsid_t f_fsid;
        int  f_namelen;
        int  f_frsize;
-       int  f_spare[5];
+       int  f_flags;
+       int  f_spare[4];
 };
 
 struct statfs64 {
@@ -47,7 +48,8 @@ struct statfs64 {
        __kernel_fsid_t f_fsid;
        int  f_namelen;
        int  f_frsize;
-       int  f_spare[5];
+       int  f_flags;
+       int  f_spare[4];
 };
 
 struct compat_statfs64 {
@@ -61,7 +63,8 @@ struct compat_statfs64 {
        __kernel_fsid_t f_fsid;
        __u32 f_namelen;
        __u32 f_frsize;
-       __u32 f_spare[5];
+       __u32 f_flags;
+       __u32 f_spare[4];
 };
 
 #endif /* __s390x__ */
index 6a30570..30ea8c8 100644 (file)
@@ -2,11 +2,49 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/file.h>
+#include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/statfs.h>
 #include <linux/security.h>
 #include <linux/uaccess.h>
 
+static int flags_by_mnt(int mnt_flags)
+{
+       int flags = 0;
+
+       if (mnt_flags & MNT_READONLY)
+               flags |= ST_RDONLY;
+       if (mnt_flags & MNT_NOSUID)
+               flags |= ST_NOSUID;
+       if (mnt_flags & MNT_NODEV)
+               flags |= ST_NODEV;
+       if (mnt_flags & MNT_NOEXEC)
+               flags |= ST_NOEXEC;
+       if (mnt_flags & MNT_NOATIME)
+               flags |= ST_NOATIME;
+       if (mnt_flags & MNT_NODIRATIME)
+               flags |= ST_NODIRATIME;
+       if (mnt_flags & MNT_RELATIME)
+               flags |= ST_RELATIME;
+       return flags;
+}
+
+static int flags_by_sb(int s_flags)
+{
+       int flags = 0;
+       if (s_flags & MS_SYNCHRONOUS)
+               flags |= ST_SYNCHRONOUS;
+       if (s_flags & MS_MANDLOCK)
+               flags |= ST_MANDLOCK;
+       return flags;
+}
+
+static int calculate_f_flags(struct vfsmount *mnt)
+{
+       return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
+               flags_by_sb(mnt->mnt_sb->s_flags);
+}
+
 int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
 {
        int retval;
@@ -26,7 +64,12 @@ int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
 
 int vfs_statfs(struct path *path, struct kstatfs *buf)
 {
-       return statfs_by_dentry(path->dentry, buf);
+       int error;
+
+       error = statfs_by_dentry(path->dentry, buf);
+       if (!error)
+               buf->f_flags = calculate_f_flags(path->mnt);
+       return error;
 }
 EXPORT_SYMBOL(vfs_statfs);
 
@@ -69,6 +112,7 @@ static int do_statfs_native(struct path *path, struct statfs *buf)
                buf->f_fsid = st.f_fsid;
                buf->f_namelen = st.f_namelen;
                buf->f_frsize = st.f_frsize;
+               buf->f_flags = st.f_flags;
                memset(buf->f_spare, 0, sizeof(buf->f_spare));
        }
        return 0;
@@ -96,6 +140,7 @@ static int do_statfs64(struct path *path, struct statfs64 *buf)
                buf->f_fsid = st.f_fsid;
                buf->f_namelen = st.f_namelen;
                buf->f_frsize = st.f_frsize;
+               buf->f_flags = st.f_flags;
                memset(buf->f_spare, 0, sizeof(buf->f_spare));
        }
        return 0;
index 3b4fb3e..0fd28e0 100644 (file)
@@ -33,7 +33,8 @@ struct statfs {
        __kernel_fsid_t f_fsid;
        __statfs_word f_namelen;
        __statfs_word f_frsize;
-       __statfs_word f_spare[5];
+       __statfs_word f_flags;
+       __statfs_word f_spare[4];
 };
 
 /*
@@ -55,7 +56,8 @@ struct statfs64 {
        __kernel_fsid_t f_fsid;
        __statfs_word f_namelen;
        __statfs_word f_frsize;
-       __statfs_word f_spare[5];
+       __statfs_word f_flags;
+       __statfs_word f_spare[4];
 } ARCH_PACK_STATFS64;
 
 /* 
@@ -77,7 +79,8 @@ struct compat_statfs64 {
        __kernel_fsid_t f_fsid;
        __u32 f_namelen;
        __u32 f_frsize;
-       __u32 f_spare[5];
+       __u32 f_flags;
+       __u32 f_spare[4];
 } ARCH_PACK_COMPAT_STATFS64;
 
 #endif
index b34cc82..0166d32 100644 (file)
@@ -2,7 +2,6 @@
 #define _LINUX_STATFS_H
 
 #include <linux/types.h>
-
 #include <asm/statfs.h>
 
 struct kstatfs {
@@ -16,7 +15,29 @@ struct kstatfs {
        __kernel_fsid_t f_fsid;
        long f_namelen;
        long f_frsize;
-       long f_spare[5];
+       long f_flags;
+       long f_spare[4];
 };
 
+/*
+ * Definitions for the flag in f_flag.
+ *
+ * Generally these flags are equivalent to the MS_ flags used in the mount
+ * ABI.  The exception is ST_VALID which has the same value as MS_REMOUNT
+ * which doesn't make any sense for statfs.
+ */
+#define ST_RDONLY      0x0001  /* mount read-only */
+#define ST_NOSUID      0x0002  /* ignore suid and sgid bits */
+#define ST_NODEV       0x0004  /* disallow access to device special files */
+#define ST_NOEXEC      0x0008  /* disallow program execution */
+#define ST_SYNCHRONOUS 0x0010  /* writes are synced at once */
+#define ST_VALID       0x0020  /* f_flags support is implemented */
+#define ST_MANDLOCK    0x0040  /* allow mandatory locks on an FS */
+/* 0x0080 used for ST_WRITE in glibc */
+/* 0x0100 used for ST_APPEND in glibc */
+/* 0x0200 used for ST_IMMUTABLE in glibc */
+#define ST_NOATIME     0x0400  /* do not update access times */
+#define ST_NODIRATIME  0x0800  /* do not update directory access times */
+#define ST_RELATIME    0x1000  /* update atime relative to mtime/ctime */
+
 #endif