linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 2/4] quota: add project quota support
@ 2014-09-10  3:54 Li Xi
  2014-09-10 19:47 ` Jan Kara
  0 siblings, 1 reply; 3+ messages in thread
From: Li Xi @ 2014-09-10  3:54 UTC (permalink / raw)
  To: linux-fsdevel@vger.kernel.org, Ext4 Developers List,
	Theodore Ts'o, Andreas Dilger, viro@zeniv.linux.org.uk,
	hch@infradead.org, Jan Kara, Dmitry Monakhov

Adds project ID support for ext4

This patch adds a new internal field of ext4 inode to save project
identifier. Also a new flag EXT4_INODE_PROJINHERIT is added for
inheriting project ID from parent directory.

Signed-off-by: Li Xi <lixi <at> ddn.com>
---
Index: linux.git/fs/ext4/ialloc.c
===================================================================
--- linux.git.orig/fs/ext4/ialloc.c
+++ linux.git/fs/ext4/ialloc.c
@@ -756,6 +756,16 @@ struct inode *__ext4_new_inode(handle_t
         inode->i_gid = dir->i_gid;
     } else
         inode_init_owner(inode, dir, mode);
+#ifdef CONFIG_QUOTA_PROJECT
+    if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+        if (ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) {
+            ei->i_projid = EXT4_I(dir)->i_projid;
+        } else {
+            ei->i_projid =
+                make_kprojid(&init_user_ns, EXT4_DEF_PROJID);
+        }
+    }
+#endif
     dquot_initialize(inode);

     if (!goal)
Index: linux.git/fs/ext4/ext4.h
===================================================================
--- linux.git.orig/fs/ext4/ext4.h
+++ linux.git/fs/ext4/ext4.h
@@ -386,16 +386,18 @@ struct flex_groups {
 #define EXT4_EA_INODE_FL            0x00200000 /* Inode used for large EA */
 #define EXT4_EOFBLOCKS_FL        0x00400000 /* Blocks allocated beyond EOF */
 #define EXT4_INLINE_DATA_FL        0x10000000 /* Inode has inline data. */
+#define EXT4_PROJINHERIT_FL        0x20000000 /* Create with parents projid */
 #define EXT4_RESERVED_FL        0x80000000 /* reserved for ext4 lib */

-#define EXT4_FL_USER_VISIBLE        0x004BDFFF /* User visible flags */
-#define EXT4_FL_USER_MODIFIABLE        0x004380FF /* User modifiable flags */
+#define EXT4_FL_USER_VISIBLE        0x204BDFFF /* User visible flags */
+#define EXT4_FL_USER_MODIFIABLE        0x204380FF /* User modifiable flags */

 /* Flags that should be inherited by new inodes from their parent. */
 #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
                EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
                EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
-               EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
+               EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\
+               EXT4_PROJINHERIT_FL)

 /* Flags that are appropriate for regular files (all but dir-specific ones). */
 #define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL))
@@ -443,6 +445,7 @@ enum {
     EXT4_INODE_EA_INODE    = 21,    /* Inode used for large EA */
     EXT4_INODE_EOFBLOCKS    = 22,    /* Blocks allocated beyond EOF */
     EXT4_INODE_INLINE_DATA    = 28,    /* Data in inode. */
+    EXT4_INODE_PROJINHERIT    = 29,    /* Create with parents projid */
     EXT4_INODE_RESERVED    = 31,    /* reserved for ext4 lib */
 };

@@ -695,6 +698,7 @@ struct ext4_inode {
     __le32  i_crtime;       /* File Creation time */
     __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
     __le32  i_version_hi;    /* high 32 bits for 64-bit version */
+    __le32  i_projid;    /* Project ID */
 };

 struct move_extent {
@@ -943,6 +947,9 @@ struct ext4_inode_info {

     /* Precomputed uuid+inum+igen checksum for seeding inode checksums */
     __u32 i_csum_seed;
+#ifdef CONFIG_QUOTA_PROJECT
+    kprojid_t i_projid;
+#endif
 };

 /*
@@ -1525,6 +1532,7 @@ static inline void ext4_clear_state_flag
  * GDT_CSUM bits are mutually exclusive.
  */
 #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM    0x0400
+#define EXT4_FEATURE_RO_COMPAT_PROJECT        0x1000 /* Project quota */

 #define EXT4_FEATURE_INCOMPAT_COMPRESSION    0x0001
 #define EXT4_FEATURE_INCOMPAT_FILETYPE        0x0002
@@ -1574,7 +1582,8 @@ static inline void ext4_clear_state_flag
                      EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
                      EXT4_FEATURE_RO_COMPAT_BIGALLOC |\
                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\
-                     EXT4_FEATURE_RO_COMPAT_QUOTA)
+                     EXT4_FEATURE_RO_COMPAT_QUOTA |\
+                     EXT4_FEATURE_RO_COMPAT_PROJECT)

 /*
  * Default values for user and/or group using reserved blocks
@@ -1582,6 +1591,11 @@ static inline void ext4_clear_state_flag
 #define    EXT4_DEF_RESUID        0
 #define    EXT4_DEF_RESGID        0

+/*
+ * Default project ID
+ */
+#define    EXT4_DEF_PROJID        0
+
 #define EXT4_DEF_INODE_READAHEAD_BLKS    32

 /*
@@ -2133,6 +2147,9 @@ extern int ext4_zero_partial_blocks(hand
                  loff_t lstart, loff_t lend);
 extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern qsize_t *ext4_get_reserved_space(struct inode *inode);
+#ifdef CONFIG_QUOTA_PROJECT
+extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
+#endif
 extern void ext4_da_update_reserve_space(struct inode *inode,
                     int used, int quota_claim);

Index: linux.git/fs/ext4/inode.c
===================================================================
--- linux.git.orig/fs/ext4/inode.c
+++ linux.git/fs/ext4/inode.c
@@ -4026,6 +4026,47 @@ static inline void ext4_iget_extra_inode
         EXT4_I(inode)->i_inline_off = 0;
 }

+#ifdef CONFIG_QUOTA_PROJECT
+static int ext4_inode_projid_get(struct inode *inode, struct ext4_inode *raw,
+                 struct ext4_inode_info *ei, projid_t *projid)
+{
+    BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+            EXT4_FEATURE_RO_COMPAT_PROJECT));
+
+    if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
+        EXT4_FITS_IN_INODE(raw, ei, i_projid)) {
+        *projid = (projid_t)le32_to_cpu(raw->i_projid);
+        return 0;
+    }
+    return -EFBIG;
+}
+
+static int ext4_inode_projid_set(struct inode *inode, struct ext4_inode *raw,
+                 struct ext4_inode_info *ei, projid_t projid)
+{
+    BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+            EXT4_FEATURE_RO_COMPAT_PROJECT));
+
+    if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
+        EXT4_FITS_IN_INODE(raw, ei, i_projid)) {
+        raw->i_projid = cpu_to_le32(projid);
+        return 0;
+    }
+    return -EFBIG;
+}
+
+int ext4_get_projid(struct inode *inode, kprojid_t *projid)
+{
+    if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+            EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+        return -ENOTSUPP;
+    }
+
+    *projid = EXT4_I(inode)->i_projid;
+    return 0;
+}
+#endif
+
 struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
 {
     struct ext4_iloc iloc;
@@ -4037,6 +4078,9 @@ struct inode *ext4_iget(struct super_blo
     int block;
     uid_t i_uid;
     gid_t i_gid;
+#ifdef CONFIG_QUOTA_PROJECT
+    projid_t i_projid = 0;
+#endif

     inode = iget_locked(sb, ino);
     if (!inode)
@@ -4087,12 +4131,26 @@ struct inode *ext4_iget(struct super_blo
     inode->i_mode = le16_to_cpu(raw_inode->i_mode);
     i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
     i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+#ifdef CONFIG_QUOTA_PROJECT
+    if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+        ret = ext4_inode_projid_get(inode, raw_inode, ei, &i_projid);
+        if (ret) {
+            EXT4_ERROR_INODE(inode, "failed to get project ID");
+            goto bad_inode;
+        }
+    }
+#endif
+
     if (!(test_opt(inode->i_sb, NO_UID32))) {
         i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
         i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
     }
     i_uid_write(inode, i_uid);
     i_gid_write(inode, i_gid);
+#ifdef CONFIG_QUOTA_PROJECT
+    if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
+        ei->i_projid = make_kprojid(&init_user_ns, i_projid);;
+#endif
     set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));

     ext4_clear_state_flags(ei);    /* Only relevant on 32-bit archs */
@@ -4315,6 +4373,9 @@ static int ext4_do_update_inode(handle_t
     int need_datasync = 0, set_large_file = 0;
     uid_t i_uid;
     gid_t i_gid;
+#ifdef CONFIG_QUOTA_PROJECT
+    projid_t i_projid = 0;
+#endif

     spin_lock(&ei->i_raw_lock);

@@ -4327,6 +4388,10 @@ static int ext4_do_update_inode(handle_t
     raw_inode->i_mode = cpu_to_le16(inode->i_mode);
     i_uid = i_uid_read(inode);
     i_gid = i_gid_read(inode);
+#ifdef CONFIG_QUOTA_PROJECT
+    if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
+        i_projid = from_kprojid(&init_user_ns, ei->i_projid);
+#endif
     if (!(test_opt(inode->i_sb, NO_UID32))) {
         raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
         raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
@@ -4356,7 +4421,8 @@ static int ext4_do_update_inode(handle_t
     EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
     EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);

-    if (ext4_inode_blocks_set(handle, raw_inode, ei)) {
+    err = ext4_inode_blocks_set(handle, raw_inode, ei);
+    if (err) {
         spin_unlock(&ei->i_raw_lock);
         goto out_brelse;
     }
@@ -4407,6 +4473,16 @@ static int ext4_do_update_inode(handle_t

     ext4_inode_csum_set(inode, raw_inode, ei);

+#ifdef CONFIG_QUOTA_PROJECT
+    if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+        err = ext4_inode_projid_set(inode, raw_inode, ei, i_projid);
+        if (err) {
+            spin_unlock(&ei->i_raw_lock);
+            goto out_brelse;
+        }
+    }
+#endif
+
     spin_unlock(&ei->i_raw_lock);

     BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
Index: linux.git/fs/ext4/super.c
===================================================================
--- linux.git.orig/fs/ext4/super.c
+++ linux.git/fs/ext4/super.c
@@ -1080,6 +1080,9 @@ static const struct dquot_operations ext
     .write_info    = ext4_write_info,
     .alloc_dquot    = dquot_alloc,
     .destroy_dquot    = dquot_destroy,
+#ifdef CONFIG_QUOTA_PROJECT
+    .get_projid    = ext4_get_projid,
+#endif
 };

 static const struct quotactl_ops ext4_qctl_operations = {
Index: linux.git/fs/ext4/namei.c
===================================================================
--- linux.git.orig/fs/ext4/namei.c
+++ linux.git/fs/ext4/namei.c
@@ -2951,11 +2951,21 @@ static int ext4_link(struct dentry *old_
 {
     handle_t *handle;
     struct inode *inode = old_dentry->d_inode;
+    struct super_block *sb = dir->i_sb;
     int err, retries = 0;

     if (inode->i_nlink >= EXT4_LINK_MAX)
         return -EMLINK;

+#ifdef CONFIG_QUOTA_PROJECT
+    if ((EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT)) &&
+        (ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) &&
+        (!projid_eq(EXT4_I(dir)->i_projid,
+            EXT4_I(old_dentry->d_inode)->i_projid))) {
+        return -EXDEV;
+    }
+#endif
+
     dquot_initialize(dir);

 retry:
@@ -3191,8 +3201,18 @@ static int ext4_rename(struct inode *old
         .dentry = new_dentry,
         .inode = new_dentry->d_inode,
     };
+    struct super_block *sb = new_dir->i_sb;
     int retval;

+#ifdef CONFIG_QUOTA_PROJECT
+    if ((EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT)) &&
+        (ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT)) &&
+        (!projid_eq(EXT4_I(new_dir)->i_projid,
+            EXT4_I(old_dentry->d_inode)->i_projid))) {
+        return -EXDEV;
+    }
+#endif
+
     dquot_initialize(old.dir);
     dquot_initialize(new.dir);

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v3 2/4] quota: add project quota support
  2014-09-10  3:54 [PATCH v3 2/4] quota: add project quota support Li Xi
@ 2014-09-10 19:47 ` Jan Kara
  2014-09-11  7:34   ` Andreas Dilger
  0 siblings, 1 reply; 3+ messages in thread
From: Jan Kara @ 2014-09-10 19:47 UTC (permalink / raw)
  To: Li Xi
  Cc: linux-fsdevel@vger.kernel.org, Ext4 Developers List,
	Theodore Ts'o, Andreas Dilger, viro@zeniv.linux.org.uk,
	hch@infradead.org, Jan Kara, Dmitry Monakhov

On Wed 10-09-14 11:54:07, Li Xi wrote:
> Adds project ID support for ext4
> 
> This patch adds a new internal field of ext4 inode to save project
> identifier. Also a new flag EXT4_INODE_PROJINHERIT is added for
> inheriting project ID from parent directory.
> 
> Signed-off-by: Li Xi <lixi <at> ddn.com>
> ---
> Index: linux.git/fs/ext4/ialloc.c
> ===================================================================
> --- linux.git.orig/fs/ext4/ialloc.c
> +++ linux.git/fs/ext4/ialloc.c
> @@ -756,6 +756,16 @@ struct inode *__ext4_new_inode(handle_t
>          inode->i_gid = dir->i_gid;
>      } else
>          inode_init_owner(inode, dir, mode);
> +#ifdef CONFIG_QUOTA_PROJECT
> +    if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT)) {
> +        if (ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) {
> +            ei->i_projid = EXT4_I(dir)->i_projid;
> +        } else {
> +            ei->i_projid =
> +                make_kprojid(&init_user_ns, EXT4_DEF_PROJID);
> +        }
> +    }
> +#endif
  Hum, I'd just always store the default project ID in the inode (i.e., you
can remove the feature test). Then ext4_get_projid() also doesn't have to
bother checking the feature and can just return whatever is in i_projid.

>      dquot_initialize(inode);
> 
>      if (!goal)
> Index: linux.git/fs/ext4/ext4.h
> ===================================================================
> --- linux.git.orig/fs/ext4/ext4.h
> +++ linux.git/fs/ext4/ext4.h
> @@ -386,16 +386,18 @@ struct flex_groups {
>  #define EXT4_EA_INODE_FL            0x00200000 /* Inode used for large EA */
>  #define EXT4_EOFBLOCKS_FL        0x00400000 /* Blocks allocated beyond EOF */
>  #define EXT4_INLINE_DATA_FL        0x10000000 /* Inode has inline data. */
> +#define EXT4_PROJINHERIT_FL        0x20000000 /* Create with parents projid */
  Why not use the next available flag - 0x00800000?


>  #define EXT4_RESERVED_FL        0x80000000 /* reserved for ext4 lib */
> 
> -#define EXT4_FL_USER_VISIBLE        0x004BDFFF /* User visible flags */
> -#define EXT4_FL_USER_MODIFIABLE        0x004380FF /* User modifiable flags */
> +#define EXT4_FL_USER_VISIBLE        0x204BDFFF /* User visible flags */
> +#define EXT4_FL_USER_MODIFIABLE        0x204380FF /* User modifiable flags */
> 
>  /* Flags that should be inherited by new inodes from their parent. */
>  #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
>                 EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
>                 EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
> -               EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
> +               EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\
> +               EXT4_PROJINHERIT_FL)
> 
>  /* Flags that are appropriate for regular files (all but dir-specific ones). */
>  #define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL))
> @@ -443,6 +445,7 @@ enum {
>      EXT4_INODE_EA_INODE    = 21,    /* Inode used for large EA */
>      EXT4_INODE_EOFBLOCKS    = 22,    /* Blocks allocated beyond EOF */
>      EXT4_INODE_INLINE_DATA    = 28,    /* Data in inode. */
> +    EXT4_INODE_PROJINHERIT    = 29,    /* Create with parents projid */
  This will need updating as well.


>      EXT4_INODE_RESERVED    = 31,    /* reserved for ext4 lib */
>  };
> 
> @@ -695,6 +698,7 @@ struct ext4_inode {
>      __le32  i_crtime;       /* File Creation time */
>      __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
>      __le32  i_version_hi;    /* high 32 bits for 64-bit version */
> +    __le32  i_projid;    /* Project ID */
>  };
> 
>  struct move_extent {
> @@ -943,6 +947,9 @@ struct ext4_inode_info {
> 
>      /* Precomputed uuid+inum+igen checksum for seeding inode checksums */
>      __u32 i_csum_seed;
> +#ifdef CONFIG_QUOTA_PROJECT
> +    kprojid_t i_projid;
> +#endif
>  };
> 
>  /*
> @@ -1525,6 +1532,7 @@ static inline void ext4_clear_state_flag
>   * GDT_CSUM bits are mutually exclusive.
>   */
>  #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM    0x0400
> +#define EXT4_FEATURE_RO_COMPAT_PROJECT        0x1000 /* Project quota */
  Why not use the next bit available - i.e. 0x0800?


>  #define EXT4_FEATURE_INCOMPAT_COMPRESSION    0x0001
>  #define EXT4_FEATURE_INCOMPAT_FILETYPE        0x0002
> @@ -1574,7 +1582,8 @@ static inline void ext4_clear_state_flag
>                       EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
>                       EXT4_FEATURE_RO_COMPAT_BIGALLOC |\
>                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\
> -                     EXT4_FEATURE_RO_COMPAT_QUOTA)
> +                     EXT4_FEATURE_RO_COMPAT_QUOTA |\
> +                     EXT4_FEATURE_RO_COMPAT_PROJECT)
> 
>  /*
>   * Default values for user and/or group using reserved blocks
> @@ -1582,6 +1591,11 @@ static inline void ext4_clear_state_flag
>  #define    EXT4_DEF_RESUID        0
>  #define    EXT4_DEF_RESGID        0
> 
> +/*
> + * Default project ID
> + */
> +#define    EXT4_DEF_PROJID        0
> +
>  #define EXT4_DEF_INODE_READAHEAD_BLKS    32
> 
>  /*
> @@ -2133,6 +2147,9 @@ extern int ext4_zero_partial_blocks(hand
>                   loff_t lstart, loff_t lend);
>  extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
>  extern qsize_t *ext4_get_reserved_space(struct inode *inode);
> +#ifdef CONFIG_QUOTA_PROJECT
> +extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
> +#endif
>  extern void ext4_da_update_reserve_space(struct inode *inode,
>                      int used, int quota_claim);
> 
> Index: linux.git/fs/ext4/inode.c
> ===================================================================
> --- linux.git.orig/fs/ext4/inode.c
> +++ linux.git/fs/ext4/inode.c
> @@ -4026,6 +4026,47 @@ static inline void ext4_iget_extra_inode
>          EXT4_I(inode)->i_inline_off = 0;
>  }
> 
> +#ifdef CONFIG_QUOTA_PROJECT
> +static int ext4_inode_projid_get(struct inode *inode, struct ext4_inode *raw,
> +                 struct ext4_inode_info *ei, projid_t *projid)
> +{
> +    BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
> +            EXT4_FEATURE_RO_COMPAT_PROJECT));
> +
> +    if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
> +        EXT4_FITS_IN_INODE(raw, ei, i_projid)) {
> +        *projid = (projid_t)le32_to_cpu(raw->i_projid);
> +        return 0;
> +    }
> +    return -EFBIG;
> +}
  Maybe you should just return the default project ID for inodes that
cannot store one?

> +
> +static int ext4_inode_projid_set(struct inode *inode, struct ext4_inode *raw,
> +                 struct ext4_inode_info *ei, projid_t projid)
> +{
> +    BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
> +            EXT4_FEATURE_RO_COMPAT_PROJECT));
> +
> +    if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
> +        EXT4_FITS_IN_INODE(raw, ei, i_projid)) {
> +        raw->i_projid = cpu_to_le32(projid);
> +        return 0;
> +    }
> +    return -EFBIG;
> +}
  The test whether project ID fits into an inode should be done when
userspace tries to set project ID for the inode in the ioctl. Thus when
we are trying to write the inode and projid doesn't fit into the inode, we
know projid is the default one and we can just avoid storing it.
ext4_inode_projid_get() will then properly interpret this as the default
projid. This way we can make project ids work reasonably for filesystems
where inode needn't have enough space.

> +int ext4_get_projid(struct inode *inode, kprojid_t *projid)
> +{
> +    if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
> +            EXT4_FEATURE_RO_COMPAT_PROJECT)) {
> +        return -ENOTSUPP;
> +    }
> +
> +    *projid = EXT4_I(inode)->i_projid;
> +    return 0;
> +}
> +#endif
> +
...

								Honza
-- 
Jan Kara <jack@suse.cz>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v3 2/4] quota: add project quota support
  2014-09-10 19:47 ` Jan Kara
@ 2014-09-11  7:34   ` Andreas Dilger
  0 siblings, 0 replies; 3+ messages in thread
From: Andreas Dilger @ 2014-09-11  7:34 UTC (permalink / raw)
  To: Jan Kara
  Cc: Li Xi, linux-fsdevel@vger.kernel.org, Ext4 Developers List,
	Theodore Ts'o, viro@zeniv.linux.org.uk, hch@infradead.org,
	Dmitry Monakhov

[-- Attachment #1: Type: text/plain, Size: 8964 bytes --]

On Sep 10, 2014, at 1:47 PM, Jan Kara <jack@suse.cz> wrote:
> On Wed 10-09-14 11:54:07, Li Xi wrote:
>> Adds project ID support for ext4
>> 
>> This patch adds a new internal field of ext4 inode to save project
>> identifier. Also a new flag EXT4_INODE_PROJINHERIT is added for
>> inheriting project ID from parent directory.
>> 
>> Signed-off-by: Li Xi <lixi <at> ddn.com>
>> ---
>> Index: linux.git/fs/ext4/ialloc.c
>> ===================================================================
>> --- linux.git.orig/fs/ext4/ialloc.c
>> +++ linux.git/fs/ext4/ialloc.c
>> @@ -756,6 +756,16 @@ struct inode *__ext4_new_inode(handle_t
>>         inode->i_gid = dir->i_gid;
>>     } else
>>         inode_init_owner(inode, dir, mode);
>> +#ifdef CONFIG_QUOTA_PROJECT
>> +    if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT)) {
>> +        if (ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) {
>> +            ei->i_projid = EXT4_I(dir)->i_projid;
>> +        } else {
>> +            ei->i_projid =
>> +                make_kprojid(&init_user_ns, EXT4_DEF_PROJID);
>> +        }
>> +    }
>> +#endif
>  Hum, I'd just always store the default project ID in the inode (i.e., you
> can remove the feature test). Then ext4_get_projid() also doesn't have to
> bother checking the feature and can just return whatever is in i_projid.

Makes sense.

>>     dquot_initialize(inode);
>> 
>>     if (!goal)
>> Index: linux.git/fs/ext4/ext4.h
>> ===================================================================
>> --- linux.git.orig/fs/ext4/ext4.h
>> +++ linux.git/fs/ext4/ext4.h
>> @@ -386,16 +386,18 @@ struct flex_groups {
>> #define EXT4_EA_INODE_FL            0x00200000 /* Inode used for large EA */
>> #define EXT4_EOFBLOCKS_FL        0x00400000 /* Blocks allocated beyond EOF */
>> #define EXT4_INLINE_DATA_FL        0x10000000 /* Inode has inline data. */
>> +#define EXT4_PROJINHERIT_FL        0x20000000 /* Create with parents projid */
>  Why not use the next available flag - 0x00800000?

Because Btrfs is using 0x00800000 for FS_NOCOW_FL, and until such a
time that we need to implement conflicting flags it would be better
to keep them non-overlapping.  It seems reasonable that since both
XFS and ext4 have a "PROJINHERIT" flag that this should also be
defined as FS_PROJINHERIT_FL to avoid other conflicts.

Please see lib/ext2fs/ext2_fs.h in newer e2fsprogs.

>> #define EXT4_RESERVED_FL        0x80000000 /* reserved for ext4 lib */
>> 
>> -#define EXT4_FL_USER_VISIBLE        0x004BDFFF /* User visible flags */
>> -#define EXT4_FL_USER_MODIFIABLE        0x004380FF /* User modifiable flags */
>> +#define EXT4_FL_USER_VISIBLE        0x204BDFFF /* User visible flags */
>> +#define EXT4_FL_USER_MODIFIABLE        0x204380FF /* User modifiable flags */
>> 
>> /* Flags that should be inherited by new inodes from their parent. */
>> #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
>>                EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
>>                EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
>> -               EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
>> +               EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\
>> +               EXT4_PROJINHERIT_FL)
>> 
>> /* Flags that are appropriate for regular files (all but dir-specific ones). */
>> #define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL))
>> @@ -443,6 +445,7 @@ enum {
>>     EXT4_INODE_EA_INODE    = 21,    /* Inode used for large EA */
>>     EXT4_INODE_EOFBLOCKS    = 22,    /* Blocks allocated beyond EOF */
>>     EXT4_INODE_INLINE_DATA    = 28,    /* Data in inode. */
>> +    EXT4_INODE_PROJINHERIT    = 29,    /* Create with parents projid */
>  This will need updating as well.

Or not...

>>     EXT4_INODE_RESERVED    = 31,    /* reserved for ext4 lib */
>> };
>> 
>> @@ -695,6 +698,7 @@ struct ext4_inode {
>>     __le32  i_crtime;       /* File Creation time */
>>     __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
>>     __le32  i_version_hi;    /* high 32 bits for 64-bit version */
>> +    __le32  i_projid;    /* Project ID */
>> };
>> 
>> struct move_extent {
>> @@ -943,6 +947,9 @@ struct ext4_inode_info {
>> 
>>     /* Precomputed uuid+inum+igen checksum for seeding inode checksums */
>>     __u32 i_csum_seed;
>> +#ifdef CONFIG_QUOTA_PROJECT
>> +    kprojid_t i_projid;
>> +#endif
>> };
>> 
>> /*
>> @@ -1525,6 +1532,7 @@ static inline void ext4_clear_state_flag
>>  * GDT_CSUM bits are mutually exclusive.
>>  */
>> #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM    0x0400
>> +#define EXT4_FEATURE_RO_COMPAT_PROJECT        0x1000 /* Project quota */
>  Why not use the next bit available - i.e. 0x0800?

That is also already in use in e2fsprogs:

    #define EXT4_FEATURE_RO_COMPAT_REPLICA          0x0800

>> #define EXT4_FEATURE_INCOMPAT_COMPRESSION    0x0001
>> #define EXT4_FEATURE_INCOMPAT_FILETYPE        0x0002
>> @@ -1574,7 +1582,8 @@ static inline void ext4_clear_state_flag
>>                      EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
>>                      EXT4_FEATURE_RO_COMPAT_BIGALLOC |\
>>                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\
>> -                     EXT4_FEATURE_RO_COMPAT_QUOTA)
>> +                     EXT4_FEATURE_RO_COMPAT_QUOTA |\
>> +                     EXT4_FEATURE_RO_COMPAT_PROJECT)
>> 
>> /*
>>  * Default values for user and/or group using reserved blocks
>> @@ -1582,6 +1591,11 @@ static inline void ext4_clear_state_flag
>> #define    EXT4_DEF_RESUID        0
>> #define    EXT4_DEF_RESGID        0
>> 
>> +/*
>> + * Default project ID
>> + */
>> +#define    EXT4_DEF_PROJID        0
>> +
>> #define EXT4_DEF_INODE_READAHEAD_BLKS    32
>> 
>> /*
>> @@ -2133,6 +2147,9 @@ extern int ext4_zero_partial_blocks(hand
>>                  loff_t lstart, loff_t lend);
>> extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
>> extern qsize_t *ext4_get_reserved_space(struct inode *inode);
>> +#ifdef CONFIG_QUOTA_PROJECT
>> +extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
>> +#endif
>> extern void ext4_da_update_reserve_space(struct inode *inode,
>>                     int used, int quota_claim);
>> 
>> Index: linux.git/fs/ext4/inode.c
>> ===================================================================
>> --- linux.git.orig/fs/ext4/inode.c
>> +++ linux.git/fs/ext4/inode.c
>> @@ -4026,6 +4026,47 @@ static inline void ext4_iget_extra_inode
>>         EXT4_I(inode)->i_inline_off = 0;
>> }
>> 
>> +#ifdef CONFIG_QUOTA_PROJECT
>> +static int ext4_inode_projid_get(struct inode *inode, struct ext4_inode *raw,
>> +                 struct ext4_inode_info *ei, projid_t *projid)
>> +{
>> +    BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
>> +            EXT4_FEATURE_RO_COMPAT_PROJECT));
>> +
>> +    if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
>> +        EXT4_FITS_IN_INODE(raw, ei, i_projid)) {
>> +        *projid = (projid_t)le32_to_cpu(raw->i_projid);
>> +        return 0;
>> +    }
>> +    return -EFBIG;
>> +}
>  Maybe you should just return the default project ID for inodes that
> cannot store one?

Sure, on the "get" side that would probably be OK.

>> +static int ext4_inode_projid_set(struct inode *inode, struct ext4_inode *raw,
>> +                 struct ext4_inode_info *ei, projid_t projid)
>> +{
>> +    BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
>> +            EXT4_FEATURE_RO_COMPAT_PROJECT));
>> +
>> +    if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
>> +        EXT4_FITS_IN_INODE(raw, ei, i_projid)) {
>> +        raw->i_projid = cpu_to_le32(projid);
>> +        return 0;
>> +    }
>> +    return -EFBIG;
>> +}
> 
>  The test whether project ID fits into an inode should be done when
> userspace tries to set project ID for the inode in the ioctl. Thus when
> we are trying to write the inode and projid doesn't fit into the inode, we
> know projid is the default one and we can just avoid storing it.
> ext4_inode_projid_get() will then properly interpret this as the default
> projid. This way we can make project ids work reasonably for filesystems
> where inode needn't have enough space.

We also have patches for e2fsprogs to allow e2fsck to resize the
i_extra_isize on existing inodes to ensure that there is always
enough space in the inode to store the project quota.

Cheers, Andreas

>> +int ext4_get_projid(struct inode *inode, kprojid_t *projid)
>> +{
>> +    if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
>> +            EXT4_FEATURE_RO_COMPAT_PROJECT)) {
>> +        return -ENOTSUPP;
>> +    }
>> +
>> +    *projid = EXT4_I(inode)->i_projid;
>> +    return 0;
>> +}
>> +#endif
>> +
> ...
> 
> 								Honza
> -- 
> Jan Kara <jack@suse.cz>
> SUSE Labs, CR


Cheers, Andreas






[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-09-11  7:34 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-10  3:54 [PATCH v3 2/4] quota: add project quota support Li Xi
2014-09-10 19:47 ` Jan Kara
2014-09-11  7:34   ` Andreas Dilger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).