Whamcloud - gitweb
LU-4017 quota: add project inherit attributes 63/26463/10
authorWang Shilong <wshilong@ddn.com>
Fri, 7 Apr 2017 01:09:18 +0000 (09:09 +0800)
committerOleg Drokin <oleg.drokin@intel.com>
Tue, 2 May 2017 03:21:18 +0000 (03:21 +0000)
Add @LUSTRE_PROJINHERIT_FL inode flag which means
creating new objects parents projid, it is disabled
in default, unless setting explictly.

It is kept same inteface as Ext4/XFS, you could use
following ioctl directly:

chattr  +P <directory>

Agent inode for DNE should ignore project ID, patch also
remove some unnecessary lustre_set_wire_obdo() call for
attr fetching/updates, which mixed la flags and obdo flags.

Change-Id: I573b71c5bd7b0089172025c30c6824562444d57d
Signed-off-by: Wang Shilong <wshilong@ddn.com>
Reviewed-on: https://review.whamcloud.com/26463
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Niu Yawei <yawei.niu@intel.com>
Reviewed-by: Li Xi <lixi@ddn.com>
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/include/lustre/lustre_idl.h
lustre/mdd/mdd_dir.c
lustre/osd-ldiskfs/osd_handler.c
lustre/target/out_handler.c
lustre/target/out_lib.c
lustre/target/update_records.c

index 89b632c..dc1e37c 100644 (file)
@@ -1621,6 +1621,7 @@ enum {
        LUSTRE_TOPDIR_FL = 0x00020000, /* Top of directory hierarchies*/
        LUSTRE_DIRECTIO_FL = 0x00100000, /* Use direct i/o */
        LUSTRE_INLINE_DATA_FL = 0x10000000, /* Inode has inline data. */
        LUSTRE_TOPDIR_FL = 0x00020000, /* Top of directory hierarchies*/
        LUSTRE_DIRECTIO_FL = 0x00100000, /* Use direct i/o */
        LUSTRE_INLINE_DATA_FL = 0x10000000, /* Inode has inline data. */
+       LUSTRE_PROJINHERIT_FL = 0x20000000, /* Create with parents projid */
 
        /* These flags will not be identical to any EXT4_*_FL counterparts,
         * and only reserved for lustre purpose. Note: these flags might
 
        /* These flags will not be identical to any EXT4_*_FL counterparts,
         * and only reserved for lustre purpose. Note: these flags might
@@ -1634,6 +1635,10 @@ enum {
        LUSTRE_LMA_FL_MASKS = LUSTRE_ORPHAN_FL,
 };
 
        LUSTRE_LMA_FL_MASKS = LUSTRE_ORPHAN_FL,
 };
 
+#ifndef FS_XFLAG_PROJINHERIT
+#define FS_XFLAG_PROJINHERIT   0x00000200      /* create with parents projid */
+#endif
+
 #ifdef __KERNEL__
 /* Convert wire LUSTRE_*_FL to corresponding client local VFS S_* values
  * for the client inode i_flags.  The LUSTRE_*_FL are the Lustre wire
 #ifdef __KERNEL__
 /* Convert wire LUSTRE_*_FL to corresponding client local VFS S_* values
  * for the client inode i_flags.  The LUSTRE_*_FL are the Lustre wire
@@ -1649,7 +1654,8 @@ static inline int ll_ext_to_inode_flags(int flags)
 #if defined(S_DIRSYNC)
                 ((flags & LUSTRE_DIRSYNC_FL)   ? S_DIRSYNC   : 0) |
 #endif
 #if defined(S_DIRSYNC)
                 ((flags & LUSTRE_DIRSYNC_FL)   ? S_DIRSYNC   : 0) |
 #endif
-                ((flags & LUSTRE_IMMUTABLE_FL) ? S_IMMUTABLE : 0));
+               ((flags & LUSTRE_IMMUTABLE_FL) ? S_IMMUTABLE : 0) |
+               ((flags & LUSTRE_PROJINHERIT_FL) ? FS_XFLAG_PROJINHERIT : 0));
 }
 
 static inline int ll_inode_to_ext_flags(int iflags)
 }
 
 static inline int ll_inode_to_ext_flags(int iflags)
@@ -1660,7 +1666,8 @@ static inline int ll_inode_to_ext_flags(int iflags)
 #if defined(S_DIRSYNC)
                 ((iflags & S_DIRSYNC)   ? LUSTRE_DIRSYNC_FL   : 0) |
 #endif
 #if defined(S_DIRSYNC)
                 ((iflags & S_DIRSYNC)   ? LUSTRE_DIRSYNC_FL   : 0) |
 #endif
-                ((iflags & S_IMMUTABLE) ? LUSTRE_IMMUTABLE_FL : 0));
+               ((iflags & S_IMMUTABLE) ? LUSTRE_IMMUTABLE_FL : 0) |
+               ((iflags & FS_XFLAG_PROJINHERIT) ? LUSTRE_PROJINHERIT_FL : 0));
 }
 #endif
 
 }
 #endif
 
index b37c795..07fe079 100644 (file)
@@ -1285,6 +1285,15 @@ static int mdd_link(const struct lu_env *env, struct md_object *tgt_obj,
        if (rc != 0)
                RETURN(rc);
 
        if (rc != 0)
                RETURN(rc);
 
+       /*
+        * If we are using project inheritance, we only allow hard link
+        * creation in our tree when the project IDs are the same;
+        * otherwise the tree quota mechanism could be circumvented.
+        */
+       if ((tattr->la_flags & LUSTRE_PROJINHERIT_FL) &&
+           (tattr->la_projid != cattr->la_projid))
+               RETURN(-EXDEV);
+
         handle = mdd_trans_create(env, mdd);
         if (IS_ERR(handle))
                 GOTO(out_pending, rc = PTR_ERR(handle));
         handle = mdd_trans_create(env, mdd);
         if (IS_ERR(handle))
                 GOTO(out_pending, rc = PTR_ERR(handle));
@@ -1942,6 +1951,16 @@ static int mdd_create_sanity_check(const struct lu_env *env,
                }
        }
 
                }
        }
 
+       /* Inherit project ID from parent directory */
+       if (pattr->la_flags & LUSTRE_PROJINHERIT_FL) {
+               cattr->la_projid = pattr->la_projid;
+               if (S_ISDIR(cattr->la_mode)) {
+                       cattr->la_flags |= LUSTRE_PROJINHERIT_FL;
+                       cattr->la_valid |= LA_FLAGS;
+               }
+               cattr->la_valid |= LA_PROJID;
+       }
+
        rc = mdd_name_check(m, lname);
        if (rc < 0)
                RETURN(rc);
        rc = mdd_name_check(m, lname);
        if (rc < 0)
                RETURN(rc);
@@ -2581,6 +2600,17 @@ static int mdd_rename_sanity_check(const struct lu_env *env,
         * before mdd_rename and enable MDS_PERM_BYPASS. */
        LASSERT(sobj);
 
         * before mdd_rename and enable MDS_PERM_BYPASS. */
        LASSERT(sobj);
 
+       /*
+        * If we are using project inheritance, we only allow renames
+        * into our tree when the project IDs are the same; otherwise
+        * tree quota mechanism would be circumvented.
+        */
+       if (((tpattr->la_flags & LUSTRE_PROJINHERIT_FL) &&
+           tpattr->la_projid != cattr->la_projid) ||
+           ((pattr->la_flags & LUSTRE_PROJINHERIT_FL) &&
+           (pattr->la_projid != tpattr->la_projid)))
+               RETURN(-EXDEV);
+
        rc = mdd_may_delete(env, src_pobj, pattr, sobj, cattr, NULL, 1, 0);
        if (rc)
                RETURN(rc);
        rc = mdd_may_delete(env, src_pobj, pattr, sobj, cattr, NULL, 1, 0);
        if (rc)
                RETURN(rc);
index dd682f5..2876e6e 100644 (file)
@@ -2382,6 +2382,13 @@ static void osd_inode_getattr(const struct lu_env *env,
        attr->la_rdev    = inode->i_rdev;
        attr->la_blksize = 1 << inode->i_blkbits;
        attr->la_blkbits = inode->i_blkbits;
        attr->la_rdev    = inode->i_rdev;
        attr->la_blksize = 1 << inode->i_blkbits;
        attr->la_blkbits = inode->i_blkbits;
+       /*
+        * Ext4 did not transfer inherit flags from raw inode
+        * to inode flags, and ext4 internally test raw inode
+        * @i_flags directly. Instead of patching ext4, we do it here.
+        */
+       if (LDISKFS_I(inode)->i_flags & LUSTRE_PROJINHERIT_FL)
+               attr->la_flags |= LUSTRE_PROJINHERIT_FL;
 }
 
 static int osd_attr_get(const struct lu_env *env,
 }
 
 static int osd_attr_get(const struct lu_env *env,
@@ -2586,6 +2593,13 @@ static int osd_inode_setattr(const struct lu_env *env,
                /* always keep S_NOCMTIME */
                inode->i_flags = ll_ext_to_inode_flags(attr->la_flags) |
                                 S_NOCMTIME;
                /* always keep S_NOCMTIME */
                inode->i_flags = ll_ext_to_inode_flags(attr->la_flags) |
                                 S_NOCMTIME;
+               /*
+                * Ext4 did not transfer inherit flags from
+                * @inode->i_flags to raw inode i_flags when writing
+                * flags, we do it explictly here.
+                */
+               if (attr->la_flags & LUSTRE_PROJINHERIT_FL)
+                       LDISKFS_I(inode)->i_flags |= LUSTRE_PROJINHERIT_FL;
        }
        return 0;
 }
        }
        return 0;
 }
@@ -2617,7 +2631,7 @@ static int osd_quota_transfer(struct inode *inode, const struct lu_attr *attr)
        }
 
 #ifdef HAVE_PROJECT_QUOTA
        }
 
 #ifdef HAVE_PROJECT_QUOTA
-       /* Handle project id Transfer here properly */
+       /* Handle project id transfer here properly */
        if (attr->la_valid & LA_PROJID && attr->la_projid !=
                                                i_projid_read(inode)) {
                rc = __ldiskfs_ioctl_setproject(inode, attr->la_projid);
        if (attr->la_valid & LA_PROJID && attr->la_projid !=
                                                i_projid_read(inode)) {
                rc = __ldiskfs_ioctl_setproject(inode, attr->la_projid);
@@ -3456,6 +3470,19 @@ static struct inode *osd_create_local_agent_inode(const struct lu_env *env,
        ldiskfs_set_inode_state(local, LDISKFS_STATE_LUSTRE_NOSCRUB);
        unlock_new_inode(local);
 
        ldiskfs_set_inode_state(local, LDISKFS_STATE_LUSTRE_NOSCRUB);
        unlock_new_inode(local);
 
+       /* Agent inode should not have project ID*/
+#ifdef HAVE_PROJECT_QUOTA
+       if (LDISKFS_I(pobj->oo_inode)->i_flags & LUSTRE_PROJINHERIT_FL) {
+               rc = __ldiskfs_ioctl_setproject(local, 0);
+               if (rc) {
+                       CERROR("%s: quota transfer failed: rc = %d. Is project "
+                              "quota enforcement enabled on the ldiskfs "
+                              "filesystem?\n", local->i_sb->s_id, rc);
+                       RETURN(ERR_PTR(rc));
+               }
+       }
+
+#endif
        /* Set special LMA flag for local agent inode */
        rc = osd_ea_fid_set(info, local, fid, 0, LMAI_AGENT);
        if (rc != 0) {
        /* Set special LMA flag for local agent inode */
        rc = osd_ea_fid_set(info, local, fid, 0, LMAI_AGENT);
        if (rc != 0) {
index 221ea37..6ad753e 100644 (file)
@@ -224,7 +224,6 @@ static int out_attr_get(struct tgt_session_info *tsi)
 
        obdo->o_valid = 0;
        obdo_from_la(obdo, la, la->la_valid);
 
        obdo->o_valid = 0;
        obdo_from_la(obdo, la, la->la_valid);
-       lustre_set_wire_obdo(NULL, obdo, obdo);
 
 out_unlock:
        dt_read_unlock(env, obj);
 
 out_unlock:
        dt_read_unlock(env, obj);
index e71484d..55b47c6 100644 (file)
@@ -215,7 +215,6 @@ int out_create_pack(const struct lu_env *env, struct object_update *update,
 
        obdo->o_valid = 0;
        obdo_from_la(obdo, attr, attr->la_valid);
 
        obdo->o_valid = 0;
        obdo_from_la(obdo, attr, attr->la_valid);
-       lustre_set_wire_obdo(NULL, obdo, obdo);
 
        if (parent_fid != NULL) {
                struct lu_fid *tmp;
 
        if (parent_fid != NULL) {
                struct lu_fid *tmp;
@@ -267,7 +266,6 @@ int out_attr_set_pack(const struct lu_env *env, struct object_update *update,
 
        obdo->o_valid = 0;
        obdo_from_la(obdo, attr, attr->la_valid);
 
        obdo->o_valid = 0;
        obdo_from_la(obdo, attr, attr->la_valid);
-       lustre_set_wire_obdo(NULL, obdo, obdo);
 
        RETURN(0);
 }
 
        RETURN(0);
 }
index ab1932d..5510bf2 100644 (file)
@@ -348,7 +348,6 @@ int update_records_create_pack(const struct lu_env *env,
                obdo = &update_env_info(env)->uti_obdo;
                obdo->o_valid = 0;
                obdo_from_la(obdo, attr, attr->la_valid);
                obdo = &update_env_info(env)->uti_obdo;
                obdo->o_valid = 0;
                obdo_from_la(obdo, attr, attr->la_valid);
-               lustre_set_wire_obdo(NULL, obdo, obdo);
                bufs[buf_count] = obdo;
                sizes[buf_count] = sizeof(*obdo);
                buf_count++;
                bufs[buf_count] = obdo;
                sizes[buf_count] = sizeof(*obdo);
                buf_count++;
@@ -422,7 +421,6 @@ int update_records_attr_set_pack(const struct lu_env *env,
 
        obdo->o_valid = 0;
        obdo_from_la(obdo, attr, attr->la_valid);
 
        obdo->o_valid = 0;
        obdo_from_la(obdo, attr, attr->la_valid);
-       lustre_set_wire_obdo(NULL, obdo, obdo);
        return update_records_update_pack(env, fid, OUT_ATTR_SET, ops, op_count,
                                          max_ops_size, params, param_count,
                                          max_param_size, 1,
        return update_records_update_pack(env, fid, OUT_ATTR_SET, ops, op_count,
                                          max_ops_size, params, param_count,
                                          max_param_size, 1,