* [v6 0/4] ext4: add project quota support
@ 2014-11-08 17:43 Li Xi
[not found] ` <1415468619-31851-1-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-08 17:43 ` [v6 4/4] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support Li Xi
0 siblings, 2 replies; 14+ messages in thread
From: Li Xi @ 2014-11-08 17:43 UTC (permalink / raw)
To: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
adilger-m1MBpc4rdrD3fQ9qLvQP4Q, jack-AlSwsSmVLrQ,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, hch-wEGCiKHe2LqWVfeAwA7xHQ,
dmonakhov-GEFAQzZX7r8dnm+yROfE0A
The following patches propose an implementation of project quota
support for ext4. A project is an aggregate of unrelated inodes
which might scatter in different directories. Inodes that belong
to the same project possess an identical identification i.e.
'project ID', just like every inode has its user/group
identification. The following patches add project quota as
supplement to the former uer/group quota types.
The semantics of ext4 project quota is consistent with XFS. Each
directory can have EXT4_INODE_PROJINHERIT flag set. When the
EXT4_INODE_PROJINHERIT flag of a parent directory is not set, a
newly created inode under that directory will have a default project
ID (i.e. 0). And its EXT4_INODE_PROJINHERIT flag is not set either.
When this flag is set on a directory, following rules will be kept:
1) The newly created inode under that directory will inherit both
the EXT4_INODE_PROJINHERIT flag and the project ID from its parent
directory.
2) Hard-linking a inode with different project ID into that directory
will fail with errno EXDEV.
3) Renaming a inode with different project ID into that directory
will fail with errno EXDEV. However, 'mv' command will detect this
failure and copy the renamed inode to a new inode in the directory.
Thus, this new inode will inherit both the project ID and
EXT4_INODE_PROJINHERIT flag.
4) If the project quota of that ID is being enforced, statfs() on
that directory will take the quotas as another upper limits along
with the capacity of the file system, i.e. the total block/inode
number will be the minimum of the quota limits and file system
capacity.
Changelog:
* v6 <- v5:
- Add project ID check for cross rename;
- Remove patch of EXT4_IOC_GETPROJECT/EXT4_IOC_SETPROJECT ioctl
* v5 <- v4:
- Check project feature when set/get project ID;
- Do not check project feature for project quota;
- Add support of FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR.
* v4 <- v3:
- Do not check project feature when set/get project ID;
- Use EXT4_MAXQUOTAS instead of MAXQUOTAS in ext4 patches;
- Remove unnecessary change of fs/quota/dquot.c;
- Remove CONFIG_QUOTA_PROJECT.
* v3 <- v2:
- Add EXT4_INODE_PROJINHERIT semantics.
* v2 <- v1:
- Add ioctl interface for setting/getting project;
- Add EXT4_FEATURE_RO_COMPAT_PROJECT;
- Add get_projid() method in struct dquot_operations;
- Add error check of ext4_inode_projid_set/get().
v5: http://www.spinics.net/lists/linux-api/msg04840.html
v4: http://lwn.net/Articles/612972/
v3: http://www.spinics.net/lists/linux-ext4/msg45184.html
v2: http://www.spinics.net/lists/linux-ext4/msg44695.html
v1: http://article.gmane.org/gmane.comp.file-systems.ext4/45153
Any comments or feedbacks are appreciated.
Regards,
- Li Xi
Li Xi (4):
vfs: adds general codes to enforces project quota limits
ext4: adds project ID support
ext4: adds project quota support
ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
fs/ext4/ext4.h | 31 ++++-
fs/ext4/ialloc.c | 6 +
fs/ext4/inode.c | 29 ++++
fs/ext4/ioctl.c | 330 +++++++++++++++++++++++++++++++-------------
fs/ext4/namei.c | 17 +++
fs/ext4/super.c | 96 +++++++++++--
fs/quota/dquot.c | 35 ++++-
fs/quota/quota.c | 8 +-
fs/quota/quotaio_v2.h | 6 +-
fs/xfs/xfs_fs.h | 17 +--
include/linux/quota.h | 2 +
include/uapi/linux/fs.h | 21 +++
include/uapi/linux/quota.h | 6 +-
13 files changed, 463 insertions(+), 141 deletions(-)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [v6 1/4] vfs: adds general codes to enforces project quota limits
[not found] ` <1415468619-31851-1-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
@ 2014-11-08 17:43 ` Li Xi
[not found] ` <1415468619-31851-2-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-08 17:43 ` [v6 2/4] ext4: adds project ID support Li Xi
2014-11-08 17:43 ` [v6 3/4] ext4: adds project quota support Li Xi
2 siblings, 1 reply; 14+ messages in thread
From: Li Xi @ 2014-11-08 17:43 UTC (permalink / raw)
To: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
adilger-m1MBpc4rdrD3fQ9qLvQP4Q, jack-AlSwsSmVLrQ,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, hch-wEGCiKHe2LqWVfeAwA7xHQ,
dmonakhov-GEFAQzZX7r8dnm+yROfE0A
This patch adds support for a new quota type PRJQUOTA for project quota
enforcement. Also a new method get_projid() is added into dquot_operations
structure.
Signed-off-by: Li Xi <lixi-LfVdkaOWEx8@public.gmane.org>
Signed-off-by: Dmitry Monakhov <dmonakhov-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
---
fs/quota/dquot.c | 35 ++++++++++++++++++++++++++++++-----
fs/quota/quota.c | 8 ++++++--
fs/quota/quotaio_v2.h | 6 ++++--
include/linux/quota.h | 2 ++
include/uapi/linux/quota.h | 6 ++++--
5 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 8b663b2..84f9bb1 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -1154,8 +1154,8 @@ static int need_print_warning(struct dquot_warn *warn)
return uid_eq(current_fsuid(), warn->w_dq_id.uid);
case GRPQUOTA:
return in_group_p(warn->w_dq_id.gid);
- case PRJQUOTA: /* Never taken... Just make gcc happy */
- return 0;
+ case PRJQUOTA:
+ return 1;
}
return 0;
}
@@ -1394,6 +1394,9 @@ static void __dquot_initialize(struct inode *inode, int type)
/* First get references to structures we might need. */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
struct kqid qid;
+ kprojid_t projid;
+ int rc;
+
got[cnt] = NULL;
if (type != -1 && cnt != type)
continue;
@@ -1404,6 +1407,10 @@ static void __dquot_initialize(struct inode *inode, int type)
*/
if (inode->i_dquot[cnt])
continue;
+
+ if (!sb_has_quota_active(sb, cnt))
+ continue;
+
init_needed = 1;
switch (cnt) {
@@ -1413,6 +1420,12 @@ static void __dquot_initialize(struct inode *inode, int type)
case GRPQUOTA:
qid = make_kqid_gid(inode->i_gid);
break;
+ case PRJQUOTA:
+ rc = inode->i_sb->dq_op->get_projid(inode, &projid);
+ if (rc)
+ continue;
+ qid = make_kqid_projid(projid);
+ break;
}
got[cnt] = dqget(sb, qid);
}
@@ -2156,7 +2169,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
error = -EROFS;
goto out_fmt;
}
- if (!sb->s_op->quota_write || !sb->s_op->quota_read) {
+ if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
+ (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
error = -EINVAL;
goto out_fmt;
}
@@ -2397,8 +2411,19 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
memset(di, 0, sizeof(*di));
di->d_version = FS_DQUOT_VERSION;
- di->d_flags = dquot->dq_id.type == USRQUOTA ?
- FS_USER_QUOTA : FS_GROUP_QUOTA;
+ switch (dquot->dq_id.type) {
+ case USRQUOTA:
+ di->d_flags = FS_USER_QUOTA;
+ break;
+ case GRPQUOTA:
+ di->d_flags = FS_GROUP_QUOTA;
+ break;
+ case PRJQUOTA:
+ di->d_flags = FS_PROJ_QUOTA;
+ break;
+ default:
+ BUG();
+ }
di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);
spin_lock(&dq_data_lock);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 7562164..795d694 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -30,11 +30,15 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
case Q_XGETQSTATV:
case Q_XQUOTASYNC:
break;
- /* allow to query information for dquots we "own" */
+ /*
+ * allow to query information for dquots we "own"
+ * always allow querying project quota
+ */
case Q_GETQUOTA:
case Q_XGETQUOTA:
if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
- (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
+ (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))) ||
+ (type == PRJQUOTA))
break;
/*FALLTHROUGH*/
default:
diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h
index f1966b4..4e95430 100644
--- a/fs/quota/quotaio_v2.h
+++ b/fs/quota/quotaio_v2.h
@@ -13,12 +13,14 @@
*/
#define V2_INITQMAGICS {\
0xd9c01f11, /* USRQUOTA */\
- 0xd9c01927 /* GRPQUOTA */\
+ 0xd9c01927, /* GRPQUOTA */\
+ 0xd9c03f14, /* PRJQUOTA */\
}
#define V2_INITQVERSIONS {\
1, /* USRQUOTA */\
- 1 /* GRPQUOTA */\
+ 1, /* GRPQUOTA */\
+ 1, /* PRJQUOTA */\
}
/* First generic header */
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 80d345a..f1b25f8 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -50,6 +50,7 @@
#undef USRQUOTA
#undef GRPQUOTA
+#undef PRJQUOTA
enum quota_type {
USRQUOTA = 0, /* element used for user quotas */
GRPQUOTA = 1, /* element used for group quotas */
@@ -312,6 +313,7 @@ struct dquot_operations {
/* get reserved quota for delayed alloc, value returned is managed by
* quota code only */
qsize_t *(*get_reserved_space) (struct inode *);
+ int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */
};
struct path;
diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h
index 3b6cfbe..b2d9486 100644
--- a/include/uapi/linux/quota.h
+++ b/include/uapi/linux/quota.h
@@ -36,11 +36,12 @@
#include <linux/errno.h>
#include <linux/types.h>
-#define __DQUOT_VERSION__ "dquot_6.5.2"
+#define __DQUOT_VERSION__ "dquot_6.6.0"
-#define MAXQUOTAS 2
+#define MAXQUOTAS 3
#define USRQUOTA 0 /* element used for user quotas */
#define GRPQUOTA 1 /* element used for group quotas */
+#define PRJQUOTA 2 /* element used for project quotas */
/*
* Definitions for the default names of the quotas files.
@@ -48,6 +49,7 @@
#define INITQFNAMES { \
"user", /* USRQUOTA */ \
"group", /* GRPQUOTA */ \
+ "project", /* PRJQUOTA */ \
"undefined", \
};
--
1.7.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [v6 2/4] ext4: adds project ID support
[not found] ` <1415468619-31851-1-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-08 17:43 ` [v6 1/4] vfs: adds general codes to enforces project quota limits Li Xi
@ 2014-11-08 17:43 ` Li Xi
2014-11-10 22:21 ` Andreas Dilger
` (2 more replies)
2014-11-08 17:43 ` [v6 3/4] ext4: adds project quota support Li Xi
2 siblings, 3 replies; 14+ messages in thread
From: Li Xi @ 2014-11-08 17:43 UTC (permalink / raw)
To: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
adilger-m1MBpc4rdrD3fQ9qLvQP4Q, jack-AlSwsSmVLrQ,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, hch-wEGCiKHe2LqWVfeAwA7xHQ,
dmonakhov-GEFAQzZX7r8dnm+yROfE0A
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-LfVdkaOWEx8@public.gmane.org>
---
fs/ext4/ext4.h | 21 +++++++++++++++++----
fs/ext4/ialloc.c | 6 ++++++
fs/ext4/inode.c | 29 +++++++++++++++++++++++++++++
fs/ext4/namei.c | 17 +++++++++++++++++
fs/ext4/super.c | 1 +
5 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index c55a1fa..d30dfa6 100644
--- a/fs/ext4/ext4.h
+++ b/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 */
};
@@ -694,6 +697,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,7 @@ struct ext4_inode_info {
/* Precomputed uuid+inum+igen checksum for seeding inode checksums */
__u32 i_csum_seed;
+ kprojid_t i_projid;
};
/*
@@ -1526,6 +1531,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
* 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
@@ -1575,7 +1581,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
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
@@ -1583,6 +1590,11 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
#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
/*
@@ -2135,6 +2147,7 @@ extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
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);
+extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
extern void ext4_da_update_reserve_space(struct inode *inode,
int used, int quota_claim);
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index ac644c3..fefb948 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -756,6 +756,12 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
inode->i_gid = dir->i_gid;
} else
inode_init_owner(inode, dir, mode);
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
+ 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);
+ }
dquot_initialize(inode);
if (!goal)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 3356ab5..1c440be 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3886,6 +3886,14 @@ static inline void ext4_iget_extra_inode(struct inode *inode,
EXT4_I(inode)->i_inline_off = 0;
}
+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 -EOPNOTSUPP;
+ *projid = EXT4_I(inode)->i_projid;
+ return 0;
+}
+
struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
{
struct ext4_iloc iloc;
@@ -3897,6 +3905,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
int block;
uid_t i_uid;
gid_t i_gid;
+ projid_t i_projid;
inode = iget_locked(sb, ino);
if (!inode)
@@ -3946,12 +3955,18 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
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);
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
+ i_projid = (projid_t)le32_to_cpu(raw_inode->i_projid);
+ else
+ i_projid = EXT4_DEF_PROJID;
+
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);
+ ei->i_projid = make_kprojid(&init_user_ns, i_projid);;
set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */
@@ -4181,6 +4196,7 @@ static int ext4_do_update_inode(handle_t *handle,
int need_datasync = 0, set_large_file = 0;
uid_t i_uid;
gid_t i_gid;
+ projid_t i_projid;
spin_lock(&ei->i_raw_lock);
@@ -4193,6 +4209,7 @@ static int ext4_do_update_inode(handle_t *handle,
raw_inode->i_mode = cpu_to_le16(inode->i_mode);
i_uid = i_uid_read(inode);
i_gid = i_gid_read(inode);
+ i_projid = from_kprojid(&init_user_ns, ei->i_projid);
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));
@@ -4272,6 +4289,18 @@ static int ext4_do_update_inode(handle_t *handle,
}
}
+ BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_RO_COMPAT_PROJECT) &&
+ i_projid != EXT4_DEF_PROJID);
+ if (i_projid != EXT4_DEF_PROJID &&
+ (EXT4_INODE_SIZE(inode->i_sb) <= EXT4_GOOD_OLD_INODE_SIZE ||
+ (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)))) {
+ spin_unlock(&ei->i_raw_lock);
+ err = -EFBIG;
+ goto out_brelse;
+ }
+ raw_inode->i_projid = cpu_to_le32(i_projid);
+
ext4_inode_csum_set(inode, raw_inode, ei);
spin_unlock(&ei->i_raw_lock);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 4262118..160a743 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2939,6 +2939,11 @@ static int ext4_link(struct dentry *old_dentry,
if (inode->i_nlink >= EXT4_LINK_MAX)
return -EMLINK;
+ if ((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;
+
dquot_initialize(dir);
retry:
@@ -3218,6 +3223,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
int credits;
u8 old_file_type;
+ if ((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;
+
dquot_initialize(old.dir);
dquot_initialize(new.dir);
@@ -3396,6 +3406,13 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
u8 new_file_type;
int retval;
+ if ((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)) ||
+ (!projid_eq(EXT4_I(old_dir)->i_projid,
+ EXT4_I(new_dentry->d_inode)->i_projid))))
+ return -EXDEV;
+
dquot_initialize(old.dir);
dquot_initialize(new.dir);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 2c9e686..d8a348d 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1077,6 +1077,7 @@ static const struct dquot_operations ext4_quota_operations = {
.write_info = ext4_write_info,
.alloc_dquot = dquot_alloc,
.destroy_dquot = dquot_destroy,
+ .get_projid = ext4_get_projid,
};
static const struct quotactl_ops ext4_qctl_operations = {
--
1.7.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [v6 3/4] ext4: adds project quota support
[not found] ` <1415468619-31851-1-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-08 17:43 ` [v6 1/4] vfs: adds general codes to enforces project quota limits Li Xi
2014-11-08 17:43 ` [v6 2/4] ext4: adds project ID support Li Xi
@ 2014-11-08 17:43 ` Li Xi
[not found] ` <1415468619-31851-4-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2 siblings, 1 reply; 14+ messages in thread
From: Li Xi @ 2014-11-08 17:43 UTC (permalink / raw)
To: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
adilger-m1MBpc4rdrD3fQ9qLvQP4Q, jack-AlSwsSmVLrQ,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, hch-wEGCiKHe2LqWVfeAwA7xHQ,
dmonakhov-GEFAQzZX7r8dnm+yROfE0A
This patch adds mount options for enabling/disabling project quota
accounting and enforcement. A new specific inode is also used for
project quota accounting.
Signed-off-by: Li Xi <lixi-LfVdkaOWEx8@public.gmane.org>
Signed-off-by: Dmitry Monakhov <dmonakhov-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
---
fs/ext4/ext4.h | 8 +++-
fs/ext4/super.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 90 insertions(+), 13 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index d30dfa6..4c797da 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -217,6 +217,7 @@ struct ext4_io_submit {
#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */
#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */
#define EXT4_JOURNAL_INO 8 /* Journal inode */
+#define EXT4_PRJ_QUOTA_INO 9 /* Project quota inode */
/* First non-reserved inode for old ext4 filesystems */
#define EXT4_GOOD_OLD_FIRST_INO 11
@@ -991,6 +992,7 @@ struct ext4_inode_info {
#define EXT4_MOUNT_DIOREAD_NOLOCK 0x400000 /* Enable support for dio read nolocking */
#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */
#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
+#define EXT4_MOUNT_PRJQUOTA 0x2000000 /* Project quota support */
#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
@@ -1166,7 +1168,8 @@ struct ext4_super_block {
__le32 s_grp_quota_inum; /* inode for tracking group quota */
__le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
__le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
- __le32 s_reserved[106]; /* Padding to the end of the block */
+ __le32 s_prj_quota_inum; /* inode for tracking project quota */
+ __le32 s_reserved[105]; /* Padding to the end of the block */
__le32 s_checksum; /* crc32c(superblock) */
};
@@ -1181,7 +1184,7 @@ struct ext4_super_block {
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
/* Number of quota types we support */
-#define EXT4_MAXQUOTAS 2
+#define EXT4_MAXQUOTAS 3
/*
* fourth extended-fs super-block data in memory
@@ -1372,6 +1375,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
ino == EXT4_BOOT_LOADER_INO ||
ino == EXT4_JOURNAL_INO ||
ino == EXT4_RESIZE_INO ||
+ ino == EXT4_PRJ_QUOTA_INO ||
(ino >= EXT4_FIRST_INO(sb) &&
ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d8a348d..564fbd7 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1045,8 +1045,8 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page,
}
#ifdef CONFIG_QUOTA
-#define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group")
-#define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
+static char *quotatypes[] = INITQFNAMES;
+#define QTYPE2NAME(t) (quotatypes[t])
static int ext4_write_dquot(struct dquot *dquot);
static int ext4_acquire_dquot(struct dquot *dquot);
@@ -1138,10 +1138,11 @@ enum {
Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
Opt_data_err_abort, Opt_data_err_ignore,
- Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
+ Opt_usrjquota, Opt_grpjquota, Opt_prjjquota,
+ Opt_offusrjquota, Opt_offgrpjquota, Opt_offprjjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
- Opt_usrquota, Opt_grpquota, Opt_i_version,
+ Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version,
Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
Opt_inode_readahead_blks, Opt_journal_ioprio,
@@ -1192,6 +1193,8 @@ static const match_table_t tokens = {
{Opt_usrjquota, "usrjquota=%s"},
{Opt_offgrpjquota, "grpjquota="},
{Opt_grpjquota, "grpjquota=%s"},
+ {Opt_offprjjquota, "prjjquota="},
+ {Opt_prjjquota, "prjjquota=%s"},
{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
{Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
@@ -1199,6 +1202,7 @@ static const match_table_t tokens = {
{Opt_noquota, "noquota"},
{Opt_quota, "quota"},
{Opt_usrquota, "usrquota"},
+ {Opt_prjquota, "prjquota"},
{Opt_barrier, "barrier=%u"},
{Opt_barrier, "barrier"},
{Opt_nobarrier, "nobarrier"},
@@ -1411,12 +1415,17 @@ static const struct mount_opts {
MOPT_SET | MOPT_Q},
{Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA,
MOPT_SET | MOPT_Q},
+ {Opt_prjquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_PRJQUOTA,
+ MOPT_SET | MOPT_Q},
{Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
- EXT4_MOUNT_GRPQUOTA), MOPT_CLEAR | MOPT_Q},
+ EXT4_MOUNT_GRPQUOTA | EXT4_MOUNT_PRJQUOTA),
+ MOPT_CLEAR | MOPT_Q},
{Opt_usrjquota, 0, MOPT_Q},
{Opt_grpjquota, 0, MOPT_Q},
+ {Opt_prjjquota, 0, MOPT_Q},
{Opt_offusrjquota, 0, MOPT_Q},
{Opt_offgrpjquota, 0, MOPT_Q},
+ {Opt_offprjjquota, 0, MOPT_Q},
{Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT},
{Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
{Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
@@ -1439,10 +1448,14 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
return set_qf_name(sb, USRQUOTA, &args[0]);
else if (token == Opt_grpjquota)
return set_qf_name(sb, GRPQUOTA, &args[0]);
+ else if (token == Opt_prjjquota)
+ return set_qf_name(sb, PRJQUOTA, &args[0]);
else if (token == Opt_offusrjquota)
return clear_qf_name(sb, USRQUOTA);
else if (token == Opt_offgrpjquota)
return clear_qf_name(sb, GRPQUOTA);
+ else if (token == Opt_offprjjquota)
+ return clear_qf_name(sb, PRJQUOTA);
#endif
switch (token) {
case Opt_noacl:
@@ -1668,19 +1681,28 @@ static int parse_options(char *options, struct super_block *sb,
}
#ifdef CONFIG_QUOTA
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
- (test_opt(sb, USRQUOTA) || test_opt(sb, GRPQUOTA))) {
+ (test_opt(sb, USRQUOTA) ||
+ test_opt(sb, GRPQUOTA) ||
+ test_opt(sb, PRJQUOTA))) {
ext4_msg(sb, KERN_ERR, "Cannot set quota options when QUOTA "
"feature is enabled");
return 0;
}
- if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+ if (sbi->s_qf_names[USRQUOTA] ||
+ sbi->s_qf_names[GRPQUOTA] ||
+ sbi->s_qf_names[PRJQUOTA]) {
if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
clear_opt(sb, USRQUOTA);
if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
clear_opt(sb, GRPQUOTA);
- if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) {
+ if (test_opt(sb, PRJQUOTA) && sbi->s_qf_names[PRJQUOTA])
+ clear_opt(sb, PRJQUOTA);
+
+ if (test_opt(sb, GRPQUOTA) ||
+ test_opt(sb, USRQUOTA) ||
+ test_opt(sb, PRJQUOTA)) {
ext4_msg(sb, KERN_ERR, "old and new quota "
"format mixing");
return 0;
@@ -1734,6 +1756,9 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
if (sbi->s_qf_names[GRPQUOTA])
seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
+
+ if (sbi->s_qf_names[PRJQUOTA])
+ seq_printf(seq, ",prjjquota=%s", sbi->s_qf_names[PRJQUOTA]);
#endif
}
@@ -5030,6 +5055,46 @@ restore_opts:
return err;
}
+static int ext4_statfs_project(struct super_block *sb,
+ kprojid_t projid, struct kstatfs *buf)
+{
+ struct kqid qid;
+ struct dquot *dquot;
+ u64 limit;
+ u64 curblock;
+
+ qid = make_kqid_projid(projid);
+ dquot = dqget(sb, qid);
+ if (!dquot)
+ return -ESRCH;
+ spin_lock(&dq_data_lock);
+
+ limit = dquot->dq_dqb.dqb_bsoftlimit ?
+ dquot->dq_dqb.dqb_bsoftlimit :
+ dquot->dq_dqb.dqb_bhardlimit;
+ if (limit && buf->f_blocks * buf->f_bsize > limit) {
+ curblock = dquot->dq_dqb.dqb_curspace / buf->f_bsize;
+ buf->f_blocks = limit / buf->f_bsize;
+ buf->f_bfree = buf->f_bavail =
+ (buf->f_blocks > curblock) ?
+ (buf->f_blocks - curblock) : 0;
+ }
+
+ limit = dquot->dq_dqb.dqb_isoftlimit ?
+ dquot->dq_dqb.dqb_isoftlimit :
+ dquot->dq_dqb.dqb_ihardlimit;
+ if (limit && buf->f_files > limit) {
+ buf->f_files = limit;
+ buf->f_ffree =
+ (buf->f_files > dquot->dq_dqb.dqb_curinodes) ?
+ (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
+ }
+
+ spin_unlock(&dq_data_lock);
+ dqput(dquot);
+ return 0;
+}
+
static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
@@ -5038,6 +5103,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
ext4_fsblk_t overhead = 0, resv_blocks;
u64 fsid;
s64 bfree;
+ struct inode *inode = dentry->d_inode;
resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters));
if (!test_opt(sb, MINIX_DF))
@@ -5062,6 +5128,9 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
+ if (ext4_test_inode_flag(inode, EXT4_INODE_PROJINHERIT) &&
+ sb_has_quota_limits_enabled(sb, PRJQUOTA))
+ ext4_statfs_project(sb, EXT4_I(inode)->i_projid, buf);
return 0;
}
@@ -5142,7 +5211,9 @@ static int ext4_mark_dquot_dirty(struct dquot *dquot)
/* Are we journaling quotas? */
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) ||
- sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+ sbi->s_qf_names[USRQUOTA] ||
+ sbi->s_qf_names[GRPQUOTA] ||
+ sbi->s_qf_names[PRJQUOTA]) {
dquot_mark_dquot_dirty(dquot);
return ext4_write_dquot(dquot);
} else {
@@ -5226,7 +5297,8 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
struct inode *qf_inode;
unsigned long qf_inums[EXT4_MAXQUOTAS] = {
le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
- le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
};
BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA));
@@ -5254,7 +5326,8 @@ static int ext4_enable_quotas(struct super_block *sb)
int type, err = 0;
unsigned long qf_inums[EXT4_MAXQUOTAS] = {
le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
- le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
};
sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
--
1.7.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [v6 4/4] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
2014-11-08 17:43 [v6 0/4] ext4: add project quota support Li Xi
[not found] ` <1415468619-31851-1-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
@ 2014-11-08 17:43 ` Li Xi
2014-11-10 0:05 ` Dave Chinner
2014-11-11 21:58 ` Dave Chinner
1 sibling, 2 replies; 14+ messages in thread
From: Li Xi @ 2014-11-08 17:43 UTC (permalink / raw)
To: linux-fsdevel, linux-ext4, linux-api, tytso, adilger, jack, viro,
hch, dmonakhov
This patch adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR ioctl interface
support for ext4. The interface is kept consistent with
XFS_IOC_FSGETXATTR/XFS_IOC_FSGETXATTR.
Signed-off-by: Li Xi <lixi@ddn.com>
---
fs/ext4/ext4.h | 2 +
fs/ext4/ioctl.c | 330 +++++++++++++++++++++++++++++++++--------------
fs/xfs/xfs_fs.h | 17 +--
include/uapi/linux/fs.h | 21 +++
4 files changed, 257 insertions(+), 113 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 4c797da..2d20677 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -617,6 +617,8 @@ enum {
#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
#define EXT4_IOC_SWAP_BOOT _IO('f', 17)
#define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
+#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR
+#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/*
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index bfda18a..d38b4e8 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -14,6 +14,8 @@
#include <linux/compat.h>
#include <linux/mount.h>
#include <linux/file.h>
+#include <linux/quotaops.h>
+#include <linux/quota.h>
#include <asm/uaccess.h>
#include "ext4_jbd2.h"
#include "ext4.h"
@@ -198,126 +200,220 @@ journal_err_out:
return err;
}
-long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+static int ext4_ioctl_setflags(struct file *filp, unsigned int flags)
{
struct inode *inode = file_inode(filp);
- struct super_block *sb = inode->i_sb;
struct ext4_inode_info *ei = EXT4_I(inode);
- unsigned int flags;
+ handle_t *handle = NULL;
+ int err, migrate = 0;
+ struct ext4_iloc iloc;
+ unsigned int oldflags, mask, i;
+ unsigned int jflag;
- ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
- switch (cmd) {
- case EXT4_IOC_GETFLAGS:
- ext4_get_inode_flags(ei);
- flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
- return put_user(flags, (int __user *) arg);
- case EXT4_IOC_SETFLAGS: {
- handle_t *handle = NULL;
- int err, migrate = 0;
- struct ext4_iloc iloc;
- unsigned int oldflags, mask, i;
- unsigned int jflag;
+ err = mnt_want_write_file(filp);
+ if (err)
+ return err;
- if (!inode_owner_or_capable(inode))
- return -EACCES;
+ flags = ext4_mask_flags(inode->i_mode, flags);
- if (get_user(flags, (int __user *) arg))
- return -EFAULT;
+ err = -EPERM;
+ mutex_lock(&inode->i_mutex);
+ /* Is it quota file? Do not allow user to mess with it */
+ if (IS_NOQUOTA(inode))
+ goto flags_out;
- err = mnt_want_write_file(filp);
- if (err)
- return err;
+ oldflags = ei->i_flags;
- flags = ext4_mask_flags(inode->i_mode, flags);
+ /* The JOURNAL_DATA flag is modifiable only by root */
+ jflag = flags & EXT4_JOURNAL_DATA_FL;
- err = -EPERM;
- mutex_lock(&inode->i_mutex);
- /* Is it quota file? Do not allow user to mess with it */
- if (IS_NOQUOTA(inode))
+ /*
+ * The IMMUTABLE and APPEND_ONLY flags can only be changed by
+ * the relevant capability.
+ *
+ * This test looks nicer. Thanks to Pauline Middelink
+ */
+ if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
+ if (!capable(CAP_LINUX_IMMUTABLE))
goto flags_out;
+ }
- oldflags = ei->i_flags;
-
- /* The JOURNAL_DATA flag is modifiable only by root */
- jflag = flags & EXT4_JOURNAL_DATA_FL;
-
- /*
- * The IMMUTABLE and APPEND_ONLY flags can only be changed by
- * the relevant capability.
- *
- * This test looks nicer. Thanks to Pauline Middelink
- */
- if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
- if (!capable(CAP_LINUX_IMMUTABLE))
- goto flags_out;
- }
-
- /*
- * The JOURNAL_DATA flag can only be changed by
- * the relevant capability.
- */
- if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
- if (!capable(CAP_SYS_RESOURCE))
- goto flags_out;
- }
- if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
- migrate = 1;
-
+ /*
+ * The JOURNAL_DATA flag can only be changed by
+ * the relevant capability.
+ */
+ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
+ if (!capable(CAP_SYS_RESOURCE))
+ goto flags_out;
+ }
+ if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
+ migrate = 1;
if (flags & EXT4_EOFBLOCKS_FL) {
- /* we don't support adding EOFBLOCKS flag */
- if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
- err = -EOPNOTSUPP;
- goto flags_out;
- }
- } else if (oldflags & EXT4_EOFBLOCKS_FL)
- ext4_truncate(inode);
-
- handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
- if (IS_ERR(handle)) {
- err = PTR_ERR(handle);
+ /* we don't support adding EOFBLOCKS flag */
+ if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
+ err = -EOPNOTSUPP;
goto flags_out;
}
- if (IS_SYNC(inode))
- ext4_handle_sync(handle);
- err = ext4_reserve_inode_write(handle, inode, &iloc);
- if (err)
- goto flags_err;
-
- for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
- if (!(mask & EXT4_FL_USER_MODIFIABLE))
- continue;
- if (mask & flags)
- ext4_set_inode_flag(inode, i);
- else
- ext4_clear_inode_flag(inode, i);
- }
+ } else if (oldflags & EXT4_EOFBLOCKS_FL)
+ ext4_truncate(inode);
- ext4_set_inode_flags(inode);
- inode->i_ctime = ext4_current_time(inode);
+ handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ goto flags_out;
+ }
+ if (IS_SYNC(inode))
+ ext4_handle_sync(handle);
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (err)
+ goto flags_err;
+
+ for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
+ if (!(mask & EXT4_FL_USER_MODIFIABLE))
+ continue;
+ if (mask & flags)
+ ext4_set_inode_flag(inode, i);
+ else
+ ext4_clear_inode_flag(inode, i);
+ }
- err = ext4_mark_iloc_dirty(handle, inode, &iloc);
-flags_err:
- ext4_journal_stop(handle);
- if (err)
- goto flags_out;
+ ext4_set_inode_flags(inode);
+ inode->i_ctime = ext4_current_time(inode);
- if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
- err = ext4_change_inode_journal_flag(inode, jflag);
- if (err)
- goto flags_out;
- if (migrate) {
- if (flags & EXT4_EXTENTS_FL)
- err = ext4_ext_migrate(inode);
- else
- err = ext4_ind_migrate(inode);
- }
+ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+flags_err:
+ ext4_journal_stop(handle);
+ if (err)
+ goto flags_out;
+
+ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
+ err = ext4_change_inode_journal_flag(inode, jflag);
+ if (err)
+ goto flags_out;
+ if (migrate) {
+ if (flags & EXT4_EXTENTS_FL)
+ err = ext4_ext_migrate(inode);
+ else
+ err = ext4_ind_migrate(inode);
+ }
flags_out:
- mutex_unlock(&inode->i_mutex);
- mnt_drop_write_file(filp);
+ mutex_unlock(&inode->i_mutex);
+ mnt_drop_write_file(filp);
+ return err;
+}
+
+static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
+{
+ struct inode *inode = file_inode(filp);
+ struct super_block *sb = inode->i_sb;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ int err;
+ handle_t *handle;
+ kprojid_t kprojid;
+ struct ext4_iloc iloc;
+ struct ext4_inode *raw_inode;
+
+ struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
+
+ /* Make sure caller can change project. */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (projid != EXT4_DEF_PROJID
+ && !EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_PROJECT))
+ return -EOPNOTSUPP;
+
+ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+ BUG_ON(__kprojid_val(EXT4_I(inode)->i_projid)
+ != EXT4_DEF_PROJID);
+ if (projid != EXT4_DEF_PROJID)
+ return -EOPNOTSUPP;
+ else
+ return 0;
+ }
+
+ kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
+
+ if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
+ return 0;
+
+ err = mnt_want_write_file(filp);
+ if (err)
return err;
+
+ err = -EPERM;
+ mutex_lock(&inode->i_mutex);
+ /* Is it quota file? Do not allow user to mess with it */
+ if (IS_NOQUOTA(inode))
+ goto project_out;
+
+ dquot_initialize(inode);
+
+ handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
+ EXT4_QUOTA_INIT_BLOCKS(sb) +
+ EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ goto project_out;
+ }
+
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (err)
+ goto project_stop;
+
+ raw_inode = ext4_raw_inode(&iloc);
+ if ((EXT4_INODE_SIZE(sb) <=
+ EXT4_GOOD_OLD_INODE_SIZE) ||
+ (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid))) {
+ err = -EFBIG;
+ goto project_stop;
}
+
+ transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
+ if (!transfer_to[PRJQUOTA])
+ goto project_set;
+
+ err = __dquot_transfer(inode, transfer_to);
+ dqput(transfer_to[PRJQUOTA]);
+ if (err)
+ goto project_stop;
+
+project_set:
+ EXT4_I(inode)->i_projid = kprojid;
+ inode->i_ctime = ext4_current_time(inode);
+ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+project_stop:
+ ext4_journal_stop(handle);
+project_out:
+ mutex_unlock(&inode->i_mutex);
+ mnt_drop_write_file(filp);
+ return err;
+}
+
+long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct super_block *sb = inode->i_sb;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ unsigned int flags;
+
+ ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
+
+ switch (cmd) {
+ case EXT4_IOC_GETFLAGS:
+ ext4_get_inode_flags(ei);
+ flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
+ return put_user(flags, (int __user *) arg);
+ case EXT4_IOC_SETFLAGS:
+ if (get_user(flags, (int __user *) arg))
+ return -EFAULT;
+ return ext4_ioctl_setflags(filp, flags);
case EXT4_IOC_GETVERSION:
case EXT4_IOC_GETVERSION_OLD:
return put_user(inode->i_generation, (int __user *) arg);
@@ -617,7 +713,45 @@ resizefs_out:
}
case EXT4_IOC_PRECACHE_EXTENTS:
return ext4_ext_precache(inode);
+ case EXT4_IOC_FSGETXATTR:
+ {
+ struct fsxattr fa;
+
+ memset(&fa, 0, sizeof(struct fsxattr));
+
+ ext4_get_inode_flags(ei);
+ fa.fsx_xflags = ei->i_flags & EXT4_FL_USER_VISIBLE;
+
+ if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+ fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
+ EXT4_I(inode)->i_projid);
+ }
+
+ if (copy_to_user((struct fsxattr __user *)arg,
+ &fa, sizeof(fa)))
+ return -EFAULT;
+ return 0;
+ }
+ case EXT4_IOC_FSSETXATTR:
+ {
+ struct fsxattr fa;
+ int err;
+
+ if (copy_from_user(&fa, (struct fsxattr __user *)arg,
+ sizeof(fa)))
+ return -EFAULT;
+ err = ext4_ioctl_setflags(filp, fa.fsx_xflags);
+ if (err)
+ return err;
+
+ err = ext4_ioctl_setproject(filp, fa.fsx_projid);
+ if (err)
+ return err;
+
+ return 0;
+ }
default:
return -ENOTTY;
}
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index 18dc721..5dd6013 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -36,19 +36,6 @@ struct dioattr {
#endif
/*
- * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
- */
-#ifndef HAVE_FSXATTR
-struct fsxattr {
- __u32 fsx_xflags; /* xflags field value (get/set) */
- __u32 fsx_extsize; /* extsize field value (get/set)*/
- __u32 fsx_nextents; /* nextents field value (get) */
- __u32 fsx_projid; /* project identifier (get/set) */
- unsigned char fsx_pad[12];
-};
-#endif
-
-/*
* Flags for the bs_xflags/fsx_xflags field
* There should be a one-to-one correspondence between these flags and the
* XFS_DIFLAG_s.
@@ -503,8 +490,8 @@ typedef struct xfs_swapext
#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
-#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
-#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR
+#define XFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR
#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 3735fa0..78bcb2b 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -58,6 +58,25 @@ struct inodes_stat_t {
long dummy[5]; /* padding for sysctl ABI compatibility */
};
+/*
+ * Extend attribute flags. These should be or-ed together to figure out what
+ * is valid.
+ */
+#define FSX_XFLAGS (1 << 0)
+#define FSX_EXTSIZE (1 << 1)
+#define FSX_NEXTENTS (1 << 2)
+#define FSX_PROJID (1 << 3)
+
+/*
+ * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+ __u32 fsx_xflags; /* xflags field value (get/set) */
+ __u32 fsx_extsize; /* extsize field value (get/set)*/
+ __u32 fsx_nextents; /* nextents field value (get) */
+ __u32 fsx_projid; /* project identifier (get/set) */
+ unsigned char fsx_pad[12];
+};
#define NR_FILE 8192 /* this can well be larger on a larger system */
@@ -163,6 +182,8 @@ struct inodes_stat_t {
#define FS_IOC_GETVERSION _IOR('v', 1, long)
#define FS_IOC_SETVERSION _IOW('v', 2, long)
#define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
+#define FS_IOC_FSGETXATTR _IOR('f', 31, struct fsxattr)
+#define FS_IOC_FSSETXATTR _IOW('f', 32, struct fsxattr)
#define FS_IOC32_GETFLAGS _IOR('f', 1, int)
#define FS_IOC32_SETFLAGS _IOW('f', 2, int)
#define FS_IOC32_GETVERSION _IOR('v', 1, int)
--
1.7.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [v6 4/4] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
2014-11-08 17:43 ` [v6 4/4] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support Li Xi
@ 2014-11-10 0:05 ` Dave Chinner
2014-11-11 21:58 ` Dave Chinner
1 sibling, 0 replies; 14+ messages in thread
From: Dave Chinner @ 2014-11-10 0:05 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel, linux-ext4, linux-api, tytso, adilger, jack, viro,
hch, dmonakhov
On Sun, Nov 09, 2014 at 01:43:39AM +0800, Li Xi wrote:
> This patch adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR ioctl interface
> support for ext4. The interface is kept consistent with
> XFS_IOC_FSGETXATTR/XFS_IOC_FSGETXATTR.
OK, can you split the ext4 implementation from the change of
interface? i.e. the ioctl rename really needs to stand alone in it's
own patch, because I've got to dig through reams of ext4 code that I
don't care about to review the API change.
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -617,6 +617,8 @@ enum {
> #define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
> #define EXT4_IOC_SWAP_BOOT _IO('f', 17)
> #define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
> +#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR
> +#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR
Don't obfuscate the new ext4 code like this - just use
FS_IOC_FSSETXATTR directly.
> +++ b/fs/xfs/xfs_fs.h
> @@ -36,19 +36,6 @@ struct dioattr {
> #endif
>
> /*
> - * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
> - */
> -#ifndef HAVE_FSXATTR
> -struct fsxattr {
> - __u32 fsx_xflags; /* xflags field value (get/set) */
> - __u32 fsx_extsize; /* extsize field value (get/set)*/
> - __u32 fsx_nextents; /* nextents field value (get) */
> - __u32 fsx_projid; /* project identifier (get/set) */
> - unsigned char fsx_pad[12];
> -};
> -#endif
> -
> -/*
> * Flags for the bs_xflags/fsx_xflags field
> * There should be a one-to-one correspondence between these flags and the
> * XFS_DIFLAG_s.
> @@ -503,8 +490,8 @@ typedef struct xfs_swapext
> #define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
> #define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
> #define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
> -#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
> -#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
> +#define XFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR
> +#define XFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR
Please pull these defines up into the section above this that is
commented:
/*
* ioctl commands that are used by Linux filesystems
*/
#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS
#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS
#define XFS_IOC_GETVERSION FS_IOC_GETVERSION
> #define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
> #define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
> #define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
> diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> index 3735fa0..78bcb2b 100644
> --- a/include/uapi/linux/fs.h
> +++ b/include/uapi/linux/fs.h
> @@ -58,6 +58,25 @@ struct inodes_stat_t {
> long dummy[5]; /* padding for sysctl ABI compatibility */
> };
>
> +/*
> + * Extend attribute flags. These should be or-ed together to figure out what
> + * is valid.
> + */
> +#define FSX_XFLAGS (1 << 0)
> +#define FSX_EXTSIZE (1 << 1)
> +#define FSX_NEXTENTS (1 << 2)
> +#define FSX_PROJID (1 << 3)
No, these do not belong in this header file - they are internal to
the XFS implementation. The *do not not define the contents of
fsx_xflags*. The flags defined in fsx_xflags are these:
/*
* Flags for the bs_xflags/fsx_xflags field
* There should be a one-to-one correspondence between these flags and the
* XFS_DIFLAG_s.
*/
#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
i.e. these are the flags that need to be promoted to
include/uapi/linux/fs.h, prefixed by s/XFS_XFLAG/FS_XFLAG/ and then
the definitions in fs/xfs/xfs_fs.h defined to the FS_XFLAG value.
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [v6 2/4] ext4: adds project ID support
2014-11-08 17:43 ` [v6 2/4] ext4: adds project ID support Li Xi
@ 2014-11-10 22:21 ` Andreas Dilger
[not found] ` <1415468619-31851-3-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-11 20:31 ` Jan Kara
2 siblings, 0 replies; 14+ messages in thread
From: Andreas Dilger @ 2014-11-10 22:21 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel, linux-ext4, linux-api, tytso, jack, viro, hch,
dmonakhov
[-- Attachment #1: Type: text/plain, Size: 10536 bytes --]
On Nov 8, 2014, at 10:43 AM, Li Xi <pkuelelixi@gmail.com> wrote:
> 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@ddn.com>
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index c55a1fa..d30dfa6 100644
> --- a/fs/ext4/ext4.h
> +++ b/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 */
This should probably be defined in uapi/linux/fs.h:
#define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
*/
+#define FS_PROJINHERIT_FL 0x20000000 /* Create with parent projid */
#define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib
and then here in fs/ext4/ext4.h header define it like:
#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */
+#define EXT4_PROJINHERIT_FL FS_PROJINHERIT_FL /* Create with parent projid */
so it is more clear that it is coming from the VFS definition. That also
allows accessing the PROJINHERIT flag with the normal chattr tool.
It wouldn't be a bad idea to add the other values that migrated from
ext4.h into uapi/linux/fs.h back into ext4.h in a similar manner (e.g.
FS_DIRECTIO_FL, FS_NOCOW_FL, in a separate patch) so the gaps in these values are explained.
> #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 */
> };
>
> @@ -694,6 +697,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,7 @@ struct ext4_inode_info {
>
> /* Precomputed uuid+inum+igen checksum for seeding inode checksums */
> __u32 i_csum_seed;
> + kprojid_t i_projid;
> };
>
> /*
> @@ -1526,6 +1531,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
> * 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
> @@ -1575,7 +1581,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
> 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
> @@ -1583,6 +1590,11 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
> #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
>
> /*
> @@ -2135,6 +2147,7 @@ extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
> 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);
> +extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
> extern void ext4_da_update_reserve_space(struct inode *inode,
> int used, int quota_claim);
>
> diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
> index ac644c3..fefb948 100644
> --- a/fs/ext4/ialloc.c
> +++ b/fs/ext4/ialloc.c
> @@ -756,6 +756,12 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
> inode->i_gid = dir->i_gid;
> } else
> inode_init_owner(inode, dir, mode);
> + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
> + 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);
> + }
> dquot_initialize(inode);
>
> if (!goal)
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 3356ab5..1c440be 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -3886,6 +3886,14 @@ static inline void ext4_iget_extra_inode(struct inode *inode,
> EXT4_I(inode)->i_inline_off = 0;
> }
>
> +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 -EOPNOTSUPP;
> + *projid = EXT4_I(inode)->i_projid;
> + return 0;
> +}
> +
> struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
> {
> struct ext4_iloc iloc;
> @@ -3897,6 +3905,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
> int block;
> uid_t i_uid;
> gid_t i_gid;
> + projid_t i_projid;
>
> inode = iget_locked(sb, ino);
> if (!inode)
> @@ -3946,12 +3955,18 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
> 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);
> + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
> + i_projid = (projid_t)le32_to_cpu(raw_inode->i_projid);
> + else
> + i_projid = EXT4_DEF_PROJID;
> +
> 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);
> + ei->i_projid = make_kprojid(&init_user_ns, i_projid);;
> set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
>
> ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */
> @@ -4181,6 +4196,7 @@ static int ext4_do_update_inode(handle_t *handle,
> int need_datasync = 0, set_large_file = 0;
> uid_t i_uid;
> gid_t i_gid;
> + projid_t i_projid;
>
> spin_lock(&ei->i_raw_lock);
>
> @@ -4193,6 +4209,7 @@ static int ext4_do_update_inode(handle_t *handle,
> raw_inode->i_mode = cpu_to_le16(inode->i_mode);
> i_uid = i_uid_read(inode);
> i_gid = i_gid_read(inode);
> + i_projid = from_kprojid(&init_user_ns, ei->i_projid);
> 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));
> @@ -4272,6 +4289,18 @@ static int ext4_do_update_inode(handle_t *handle,
> }
> }
>
> + BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
> + EXT4_FEATURE_RO_COMPAT_PROJECT) &&
> + i_projid != EXT4_DEF_PROJID);
> + if (i_projid != EXT4_DEF_PROJID &&
> + (EXT4_INODE_SIZE(inode->i_sb) <= EXT4_GOOD_OLD_INODE_SIZE ||
> + (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)))) {
> + spin_unlock(&ei->i_raw_lock);
> + err = -EFBIG;
> + goto out_brelse;
> + }
> + raw_inode->i_projid = cpu_to_le32(i_projid);
> +
> ext4_inode_csum_set(inode, raw_inode, ei);
>
> spin_unlock(&ei->i_raw_lock);
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index 4262118..160a743 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -2939,6 +2939,11 @@ static int ext4_link(struct dentry *old_dentry,
> if (inode->i_nlink >= EXT4_LINK_MAX)
> return -EMLINK;
>
> + if ((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;
> +
> dquot_initialize(dir);
>
> retry:
> @@ -3218,6 +3223,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
> int credits;
> u8 old_file_type;
>
> + if ((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;
> +
> dquot_initialize(old.dir);
> dquot_initialize(new.dir);
>
> @@ -3396,6 +3406,13 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
> u8 new_file_type;
> int retval;
>
> + if ((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)) ||
> + (!projid_eq(EXT4_I(old_dir)->i_projid,
> + EXT4_I(new_dentry->d_inode)->i_projid))))
> + return -EXDEV;
> +
> dquot_initialize(old.dir);
> dquot_initialize(new.dir);
>
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 2c9e686..d8a348d 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1077,6 +1077,7 @@ static const struct dquot_operations ext4_quota_operations = {
> .write_info = ext4_write_info,
> .alloc_dquot = dquot_alloc,
> .destroy_dquot = dquot_destroy,
> + .get_projid = ext4_get_projid,
> };
>
> static const struct quotactl_ops ext4_qctl_operations = {
> --
> 1.7.1
>
Cheers, Andreas
[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [v6 2/4] ext4: adds project ID support
[not found] ` <1415468619-31851-3-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
@ 2014-11-11 4:26 ` Theodore Ts'o
2014-11-11 7:34 ` Li Xi
2014-11-11 20:23 ` Jan Kara
0 siblings, 2 replies; 14+ messages in thread
From: Theodore Ts'o @ 2014-11-11 4:26 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, adilger-m1MBpc4rdrD3fQ9qLvQP4Q,
jack-AlSwsSmVLrQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
hch-wEGCiKHe2LqWVfeAwA7xHQ, dmonakhov-GEFAQzZX7r8dnm+yROfE0A
On Sun, Nov 09, 2014 at 01:43:37AM +0800, Li Xi wrote:
> 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.
What would be the downside of simply always inhereiting the project ID
from the parent directory? I see that if the flag is not set, the
project id will be 0 instead. I'm not sure when that would actually
be desirable.
To the extent that the project ID is designed to implement a quota
over a directory extent, the fact that the owner can clear the
EXT4_PROJINHERET_FL and then arrange to have the quota charged to
project 0 seems to me to be a bug, not a feature.
Can you explain what your intended use case for this flag might be?
Thanks,
- Ted
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [v6 2/4] ext4: adds project ID support
2014-11-11 4:26 ` Theodore Ts'o
@ 2014-11-11 7:34 ` Li Xi
2014-11-11 20:23 ` Jan Kara
1 sibling, 0 replies; 14+ messages in thread
From: Li Xi @ 2014-11-11 7:34 UTC (permalink / raw)
To: Theodore Ts'o
Cc: linux-fsdevel@vger.kernel.org, Ext4 Developers List,
linux-api@vger.kernel.org, Andreas Dilger, Jan Kara,
viro@zeniv.linux.org.uk, hch@infradead.org, Dmitry Monakhov
On Tue, Nov 11, 2014 at 12:26 PM, Theodore Ts'o <tytso@mit.edu> wrote:
> On Sun, Nov 09, 2014 at 01:43:37AM +0800, Li Xi wrote:
>> 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.
>
> What would be the downside of simply always inhereiting the project ID
> from the parent directory? I see that if the flag is not set, the
> project id will be 0 instead. I'm not sure when that would actually
> be desirable.
>
> To the extent that the project ID is designed to implement a quota
> over a directory extent, the fact that the owner can clear the
> EXT4_PROJINHERET_FL and then arrange to have the quota charged to
> project 0 seems to me to be a bug, not a feature.
>
Yeah, if we only intend to implement quota over directories, always inheriting
project ID from parent directory is fine. But we want this to be more flexible,
thus more powerful to enable other use cases. Always inheriting project ID
from parent means inodes uner the same subtree has the same project ID,
which might limit some use cases.
For example, if the administrator wants to track the disk usages of files
which scatter under different directories yet has similar attributes (e.g.
the sizes of them are really big), they can use project quota to archive
this goal. Combining 'find' command with setting project ID is really
convenient for this use case. And obviously, it wounldn't be possible,
if we don't have a mutable EXT4_INODE_PROJINHERIT flag.
Please note that project ID can only be change by administrator,
which means even the owners of the files can't change the project IDs.
The idea behinds it is that project quota is a tool for administrators, not
for common users.
And EXT4_INODE_PROJINHERIT is introduced into Ext4 in oder to keep
compatibile with XFS too. Otherwise, they would have different semantics. ;)
Regards,
- Li Xi
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [v6 2/4] ext4: adds project ID support
2014-11-11 4:26 ` Theodore Ts'o
2014-11-11 7:34 ` Li Xi
@ 2014-11-11 20:23 ` Jan Kara
1 sibling, 0 replies; 14+ messages in thread
From: Jan Kara @ 2014-11-11 20:23 UTC (permalink / raw)
To: Theodore Ts'o
Cc: Li Xi, linux-fsdevel, linux-ext4, linux-api, adilger, jack, viro,
hch, dmonakhov
On Mon 10-11-14 23:26:06, Ted Tso wrote:
> On Sun, Nov 09, 2014 at 01:43:37AM +0800, Li Xi wrote:
> > 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.
>
> What would be the downside of simply always inhereiting the project ID
> from the parent directory? I see that if the flag is not set, the
> project id will be 0 instead. I'm not sure when that would actually
> be desirable.
Well, 0 is a fallback project ID effectively meaning "not accounted in
project quota".
> To the extent that the project ID is designed to implement a quota
> over a directory extent, the fact that the owner can clear the
> EXT4_PROJINHERET_FL and then arrange to have the quota charged to
> project 0 seems to me to be a bug, not a feature.
>
> Can you explain what your intended use case for this flag might be?
So I agree that for directory quotas there's no reason not to inherit the
project ID. But there might be other use cases and I strongly prefer to
stay compatible with XFS as far as reasonably possible to make life for
userspace simpler.
Honza
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [v6 1/4] vfs: adds general codes to enforces project quota limits
[not found] ` <1415468619-31851-2-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
@ 2014-11-11 20:27 ` Jan Kara
0 siblings, 0 replies; 14+ messages in thread
From: Jan Kara @ 2014-11-11 20:27 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
adilger-m1MBpc4rdrD3fQ9qLvQP4Q, jack-AlSwsSmVLrQ,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, hch-wEGCiKHe2LqWVfeAwA7xHQ,
dmonakhov-GEFAQzZX7r8dnm+yROfE0A
On Sun 09-11-14 01:43:36, Li Xi wrote:
> This patch adds support for a new quota type PRJQUOTA for project quota
> enforcement. Also a new method get_projid() is added into dquot_operations
> structure.
The patch looks good. You can add:
Reviewed-by: Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
Honza
> Signed-off-by: Li Xi <lixi-LfVdkaOWEx8@public.gmane.org>
> Signed-off-by: Dmitry Monakhov <dmonakhov-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
> ---
> fs/quota/dquot.c | 35 ++++++++++++++++++++++++++++++-----
> fs/quota/quota.c | 8 ++++++--
> fs/quota/quotaio_v2.h | 6 ++++--
> include/linux/quota.h | 2 ++
> include/uapi/linux/quota.h | 6 ++++--
> 5 files changed, 46 insertions(+), 11 deletions(-)
>
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 8b663b2..84f9bb1 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -1154,8 +1154,8 @@ static int need_print_warning(struct dquot_warn *warn)
> return uid_eq(current_fsuid(), warn->w_dq_id.uid);
> case GRPQUOTA:
> return in_group_p(warn->w_dq_id.gid);
> - case PRJQUOTA: /* Never taken... Just make gcc happy */
> - return 0;
> + case PRJQUOTA:
> + return 1;
> }
> return 0;
> }
> @@ -1394,6 +1394,9 @@ static void __dquot_initialize(struct inode *inode, int type)
> /* First get references to structures we might need. */
> for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> struct kqid qid;
> + kprojid_t projid;
> + int rc;
> +
> got[cnt] = NULL;
> if (type != -1 && cnt != type)
> continue;
> @@ -1404,6 +1407,10 @@ static void __dquot_initialize(struct inode *inode, int type)
> */
> if (inode->i_dquot[cnt])
> continue;
> +
> + if (!sb_has_quota_active(sb, cnt))
> + continue;
> +
> init_needed = 1;
>
> switch (cnt) {
> @@ -1413,6 +1420,12 @@ static void __dquot_initialize(struct inode *inode, int type)
> case GRPQUOTA:
> qid = make_kqid_gid(inode->i_gid);
> break;
> + case PRJQUOTA:
> + rc = inode->i_sb->dq_op->get_projid(inode, &projid);
> + if (rc)
> + continue;
> + qid = make_kqid_projid(projid);
> + break;
> }
> got[cnt] = dqget(sb, qid);
> }
> @@ -2156,7 +2169,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
> error = -EROFS;
> goto out_fmt;
> }
> - if (!sb->s_op->quota_write || !sb->s_op->quota_read) {
> + if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
> + (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
> error = -EINVAL;
> goto out_fmt;
> }
> @@ -2397,8 +2411,19 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>
> memset(di, 0, sizeof(*di));
> di->d_version = FS_DQUOT_VERSION;
> - di->d_flags = dquot->dq_id.type == USRQUOTA ?
> - FS_USER_QUOTA : FS_GROUP_QUOTA;
> + switch (dquot->dq_id.type) {
> + case USRQUOTA:
> + di->d_flags = FS_USER_QUOTA;
> + break;
> + case GRPQUOTA:
> + di->d_flags = FS_GROUP_QUOTA;
> + break;
> + case PRJQUOTA:
> + di->d_flags = FS_PROJ_QUOTA;
> + break;
> + default:
> + BUG();
> + }
> di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);
>
> spin_lock(&dq_data_lock);
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 7562164..795d694 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -30,11 +30,15 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
> case Q_XGETQSTATV:
> case Q_XQUOTASYNC:
> break;
> - /* allow to query information for dquots we "own" */
> + /*
> + * allow to query information for dquots we "own"
> + * always allow querying project quota
> + */
> case Q_GETQUOTA:
> case Q_XGETQUOTA:
> if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
> - (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
> + (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))) ||
> + (type == PRJQUOTA))
> break;
> /*FALLTHROUGH*/
> default:
> diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h
> index f1966b4..4e95430 100644
> --- a/fs/quota/quotaio_v2.h
> +++ b/fs/quota/quotaio_v2.h
> @@ -13,12 +13,14 @@
> */
> #define V2_INITQMAGICS {\
> 0xd9c01f11, /* USRQUOTA */\
> - 0xd9c01927 /* GRPQUOTA */\
> + 0xd9c01927, /* GRPQUOTA */\
> + 0xd9c03f14, /* PRJQUOTA */\
> }
>
> #define V2_INITQVERSIONS {\
> 1, /* USRQUOTA */\
> - 1 /* GRPQUOTA */\
> + 1, /* GRPQUOTA */\
> + 1, /* PRJQUOTA */\
> }
>
> /* First generic header */
> diff --git a/include/linux/quota.h b/include/linux/quota.h
> index 80d345a..f1b25f8 100644
> --- a/include/linux/quota.h
> +++ b/include/linux/quota.h
> @@ -50,6 +50,7 @@
>
> #undef USRQUOTA
> #undef GRPQUOTA
> +#undef PRJQUOTA
> enum quota_type {
> USRQUOTA = 0, /* element used for user quotas */
> GRPQUOTA = 1, /* element used for group quotas */
> @@ -312,6 +313,7 @@ struct dquot_operations {
> /* get reserved quota for delayed alloc, value returned is managed by
> * quota code only */
> qsize_t *(*get_reserved_space) (struct inode *);
> + int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */
> };
>
> struct path;
> diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h
> index 3b6cfbe..b2d9486 100644
> --- a/include/uapi/linux/quota.h
> +++ b/include/uapi/linux/quota.h
> @@ -36,11 +36,12 @@
> #include <linux/errno.h>
> #include <linux/types.h>
>
> -#define __DQUOT_VERSION__ "dquot_6.5.2"
> +#define __DQUOT_VERSION__ "dquot_6.6.0"
>
> -#define MAXQUOTAS 2
> +#define MAXQUOTAS 3
> #define USRQUOTA 0 /* element used for user quotas */
> #define GRPQUOTA 1 /* element used for group quotas */
> +#define PRJQUOTA 2 /* element used for project quotas */
>
> /*
> * Definitions for the default names of the quotas files.
> @@ -48,6 +49,7 @@
> #define INITQFNAMES { \
> "user", /* USRQUOTA */ \
> "group", /* GRPQUOTA */ \
> + "project", /* PRJQUOTA */ \
> "undefined", \
> };
>
> --
> 1.7.1
>
--
Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [v6 2/4] ext4: adds project ID support
2014-11-08 17:43 ` [v6 2/4] ext4: adds project ID support Li Xi
2014-11-10 22:21 ` Andreas Dilger
[not found] ` <1415468619-31851-3-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
@ 2014-11-11 20:31 ` Jan Kara
2 siblings, 0 replies; 14+ messages in thread
From: Jan Kara @ 2014-11-11 20:31 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel, linux-ext4, linux-api, tytso, adilger, jack, viro,
hch, dmonakhov
On Sun 09-11-14 01:43:37, Li Xi wrote:
> 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@ddn.com>
You didn't add my Reviewed-by tag from the last round. Why is that? I was
wondering whether you significantly changed the patch since the last
submission but it doesn't seem so.
Honza
> ---
> fs/ext4/ext4.h | 21 +++++++++++++++++----
> fs/ext4/ialloc.c | 6 ++++++
> fs/ext4/inode.c | 29 +++++++++++++++++++++++++++++
> fs/ext4/namei.c | 17 +++++++++++++++++
> fs/ext4/super.c | 1 +
> 5 files changed, 70 insertions(+), 4 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index c55a1fa..d30dfa6 100644
> --- a/fs/ext4/ext4.h
> +++ b/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 */
> };
>
> @@ -694,6 +697,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,7 @@ struct ext4_inode_info {
>
> /* Precomputed uuid+inum+igen checksum for seeding inode checksums */
> __u32 i_csum_seed;
> + kprojid_t i_projid;
> };
>
> /*
> @@ -1526,6 +1531,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
> * 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
> @@ -1575,7 +1581,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
> 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
> @@ -1583,6 +1590,11 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
> #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
>
> /*
> @@ -2135,6 +2147,7 @@ extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
> 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);
> +extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
> extern void ext4_da_update_reserve_space(struct inode *inode,
> int used, int quota_claim);
>
> diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
> index ac644c3..fefb948 100644
> --- a/fs/ext4/ialloc.c
> +++ b/fs/ext4/ialloc.c
> @@ -756,6 +756,12 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
> inode->i_gid = dir->i_gid;
> } else
> inode_init_owner(inode, dir, mode);
> + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
> + 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);
> + }
> dquot_initialize(inode);
>
> if (!goal)
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 3356ab5..1c440be 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -3886,6 +3886,14 @@ static inline void ext4_iget_extra_inode(struct inode *inode,
> EXT4_I(inode)->i_inline_off = 0;
> }
>
> +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 -EOPNOTSUPP;
> + *projid = EXT4_I(inode)->i_projid;
> + return 0;
> +}
> +
> struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
> {
> struct ext4_iloc iloc;
> @@ -3897,6 +3905,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
> int block;
> uid_t i_uid;
> gid_t i_gid;
> + projid_t i_projid;
>
> inode = iget_locked(sb, ino);
> if (!inode)
> @@ -3946,12 +3955,18 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
> 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);
> + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
> + i_projid = (projid_t)le32_to_cpu(raw_inode->i_projid);
> + else
> + i_projid = EXT4_DEF_PROJID;
> +
> 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);
> + ei->i_projid = make_kprojid(&init_user_ns, i_projid);;
> set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
>
> ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */
> @@ -4181,6 +4196,7 @@ static int ext4_do_update_inode(handle_t *handle,
> int need_datasync = 0, set_large_file = 0;
> uid_t i_uid;
> gid_t i_gid;
> + projid_t i_projid;
>
> spin_lock(&ei->i_raw_lock);
>
> @@ -4193,6 +4209,7 @@ static int ext4_do_update_inode(handle_t *handle,
> raw_inode->i_mode = cpu_to_le16(inode->i_mode);
> i_uid = i_uid_read(inode);
> i_gid = i_gid_read(inode);
> + i_projid = from_kprojid(&init_user_ns, ei->i_projid);
> 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));
> @@ -4272,6 +4289,18 @@ static int ext4_do_update_inode(handle_t *handle,
> }
> }
>
> + BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
> + EXT4_FEATURE_RO_COMPAT_PROJECT) &&
> + i_projid != EXT4_DEF_PROJID);
> + if (i_projid != EXT4_DEF_PROJID &&
> + (EXT4_INODE_SIZE(inode->i_sb) <= EXT4_GOOD_OLD_INODE_SIZE ||
> + (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)))) {
> + spin_unlock(&ei->i_raw_lock);
> + err = -EFBIG;
> + goto out_brelse;
> + }
> + raw_inode->i_projid = cpu_to_le32(i_projid);
> +
> ext4_inode_csum_set(inode, raw_inode, ei);
>
> spin_unlock(&ei->i_raw_lock);
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index 4262118..160a743 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -2939,6 +2939,11 @@ static int ext4_link(struct dentry *old_dentry,
> if (inode->i_nlink >= EXT4_LINK_MAX)
> return -EMLINK;
>
> + if ((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;
> +
> dquot_initialize(dir);
>
> retry:
> @@ -3218,6 +3223,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
> int credits;
> u8 old_file_type;
>
> + if ((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;
> +
> dquot_initialize(old.dir);
> dquot_initialize(new.dir);
>
> @@ -3396,6 +3406,13 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
> u8 new_file_type;
> int retval;
>
> + if ((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)) ||
> + (!projid_eq(EXT4_I(old_dir)->i_projid,
> + EXT4_I(new_dentry->d_inode)->i_projid))))
> + return -EXDEV;
> +
> dquot_initialize(old.dir);
> dquot_initialize(new.dir);
>
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 2c9e686..d8a348d 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1077,6 +1077,7 @@ static const struct dquot_operations ext4_quota_operations = {
> .write_info = ext4_write_info,
> .alloc_dquot = dquot_alloc,
> .destroy_dquot = dquot_destroy,
> + .get_projid = ext4_get_projid,
> };
>
> static const struct quotactl_ops ext4_qctl_operations = {
> --
> 1.7.1
>
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [v6 3/4] ext4: adds project quota support
[not found] ` <1415468619-31851-4-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
@ 2014-11-11 20:34 ` Jan Kara
0 siblings, 0 replies; 14+ messages in thread
From: Jan Kara @ 2014-11-11 20:34 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
adilger-m1MBpc4rdrD3fQ9qLvQP4Q, jack-AlSwsSmVLrQ,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, hch-wEGCiKHe2LqWVfeAwA7xHQ,
dmonakhov-GEFAQzZX7r8dnm+yROfE0A
On Sun 09-11-14 01:43:38, Li Xi wrote:
> This patch adds mount options for enabling/disabling project quota
> accounting and enforcement. A new specific inode is also used for
> project quota accounting.
>
> Signed-off-by: Li Xi <lixi-LfVdkaOWEx8@public.gmane.org>
> Signed-off-by: Dmitry Monakhov <dmonakhov-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
The patch looks good. You can add:
Reviewed-by: Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
Honza
> ---
> fs/ext4/ext4.h | 8 +++-
> fs/ext4/super.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 90 insertions(+), 13 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index d30dfa6..4c797da 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -217,6 +217,7 @@ struct ext4_io_submit {
> #define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */
> #define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */
> #define EXT4_JOURNAL_INO 8 /* Journal inode */
> +#define EXT4_PRJ_QUOTA_INO 9 /* Project quota inode */
>
> /* First non-reserved inode for old ext4 filesystems */
> #define EXT4_GOOD_OLD_FIRST_INO 11
> @@ -991,6 +992,7 @@ struct ext4_inode_info {
> #define EXT4_MOUNT_DIOREAD_NOLOCK 0x400000 /* Enable support for dio read nolocking */
> #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */
> #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
> +#define EXT4_MOUNT_PRJQUOTA 0x2000000 /* Project quota support */
> #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
> #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
> #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
> @@ -1166,7 +1168,8 @@ struct ext4_super_block {
> __le32 s_grp_quota_inum; /* inode for tracking group quota */
> __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
> __le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
> - __le32 s_reserved[106]; /* Padding to the end of the block */
> + __le32 s_prj_quota_inum; /* inode for tracking project quota */
> + __le32 s_reserved[105]; /* Padding to the end of the block */
> __le32 s_checksum; /* crc32c(superblock) */
> };
>
> @@ -1181,7 +1184,7 @@ struct ext4_super_block {
> #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
>
> /* Number of quota types we support */
> -#define EXT4_MAXQUOTAS 2
> +#define EXT4_MAXQUOTAS 3
>
> /*
> * fourth extended-fs super-block data in memory
> @@ -1372,6 +1375,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
> ino == EXT4_BOOT_LOADER_INO ||
> ino == EXT4_JOURNAL_INO ||
> ino == EXT4_RESIZE_INO ||
> + ino == EXT4_PRJ_QUOTA_INO ||
> (ino >= EXT4_FIRST_INO(sb) &&
> ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
> }
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index d8a348d..564fbd7 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1045,8 +1045,8 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page,
> }
>
> #ifdef CONFIG_QUOTA
> -#define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group")
> -#define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
> +static char *quotatypes[] = INITQFNAMES;
> +#define QTYPE2NAME(t) (quotatypes[t])
>
> static int ext4_write_dquot(struct dquot *dquot);
> static int ext4_acquire_dquot(struct dquot *dquot);
> @@ -1138,10 +1138,11 @@ enum {
> Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
> Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
> Opt_data_err_abort, Opt_data_err_ignore,
> - Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
> + Opt_usrjquota, Opt_grpjquota, Opt_prjjquota,
> + Opt_offusrjquota, Opt_offgrpjquota, Opt_offprjjquota,
> Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
> Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
> - Opt_usrquota, Opt_grpquota, Opt_i_version,
> + Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version,
> Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
> Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
> Opt_inode_readahead_blks, Opt_journal_ioprio,
> @@ -1192,6 +1193,8 @@ static const match_table_t tokens = {
> {Opt_usrjquota, "usrjquota=%s"},
> {Opt_offgrpjquota, "grpjquota="},
> {Opt_grpjquota, "grpjquota=%s"},
> + {Opt_offprjjquota, "prjjquota="},
> + {Opt_prjjquota, "prjjquota=%s"},
> {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
> {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
> {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
> @@ -1199,6 +1202,7 @@ static const match_table_t tokens = {
> {Opt_noquota, "noquota"},
> {Opt_quota, "quota"},
> {Opt_usrquota, "usrquota"},
> + {Opt_prjquota, "prjquota"},
> {Opt_barrier, "barrier=%u"},
> {Opt_barrier, "barrier"},
> {Opt_nobarrier, "nobarrier"},
> @@ -1411,12 +1415,17 @@ static const struct mount_opts {
> MOPT_SET | MOPT_Q},
> {Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA,
> MOPT_SET | MOPT_Q},
> + {Opt_prjquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_PRJQUOTA,
> + MOPT_SET | MOPT_Q},
> {Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
> - EXT4_MOUNT_GRPQUOTA), MOPT_CLEAR | MOPT_Q},
> + EXT4_MOUNT_GRPQUOTA | EXT4_MOUNT_PRJQUOTA),
> + MOPT_CLEAR | MOPT_Q},
> {Opt_usrjquota, 0, MOPT_Q},
> {Opt_grpjquota, 0, MOPT_Q},
> + {Opt_prjjquota, 0, MOPT_Q},
> {Opt_offusrjquota, 0, MOPT_Q},
> {Opt_offgrpjquota, 0, MOPT_Q},
> + {Opt_offprjjquota, 0, MOPT_Q},
> {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT},
> {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
> {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
> @@ -1439,10 +1448,14 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
> return set_qf_name(sb, USRQUOTA, &args[0]);
> else if (token == Opt_grpjquota)
> return set_qf_name(sb, GRPQUOTA, &args[0]);
> + else if (token == Opt_prjjquota)
> + return set_qf_name(sb, PRJQUOTA, &args[0]);
> else if (token == Opt_offusrjquota)
> return clear_qf_name(sb, USRQUOTA);
> else if (token == Opt_offgrpjquota)
> return clear_qf_name(sb, GRPQUOTA);
> + else if (token == Opt_offprjjquota)
> + return clear_qf_name(sb, PRJQUOTA);
> #endif
> switch (token) {
> case Opt_noacl:
> @@ -1668,19 +1681,28 @@ static int parse_options(char *options, struct super_block *sb,
> }
> #ifdef CONFIG_QUOTA
> if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
> - (test_opt(sb, USRQUOTA) || test_opt(sb, GRPQUOTA))) {
> + (test_opt(sb, USRQUOTA) ||
> + test_opt(sb, GRPQUOTA) ||
> + test_opt(sb, PRJQUOTA))) {
> ext4_msg(sb, KERN_ERR, "Cannot set quota options when QUOTA "
> "feature is enabled");
> return 0;
> }
> - if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
> + if (sbi->s_qf_names[USRQUOTA] ||
> + sbi->s_qf_names[GRPQUOTA] ||
> + sbi->s_qf_names[PRJQUOTA]) {
> if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
> clear_opt(sb, USRQUOTA);
>
> if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
> clear_opt(sb, GRPQUOTA);
>
> - if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) {
> + if (test_opt(sb, PRJQUOTA) && sbi->s_qf_names[PRJQUOTA])
> + clear_opt(sb, PRJQUOTA);
> +
> + if (test_opt(sb, GRPQUOTA) ||
> + test_opt(sb, USRQUOTA) ||
> + test_opt(sb, PRJQUOTA)) {
> ext4_msg(sb, KERN_ERR, "old and new quota "
> "format mixing");
> return 0;
> @@ -1734,6 +1756,9 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
>
> if (sbi->s_qf_names[GRPQUOTA])
> seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
> +
> + if (sbi->s_qf_names[PRJQUOTA])
> + seq_printf(seq, ",prjjquota=%s", sbi->s_qf_names[PRJQUOTA]);
> #endif
> }
>
> @@ -5030,6 +5055,46 @@ restore_opts:
> return err;
> }
>
> +static int ext4_statfs_project(struct super_block *sb,
> + kprojid_t projid, struct kstatfs *buf)
> +{
> + struct kqid qid;
> + struct dquot *dquot;
> + u64 limit;
> + u64 curblock;
> +
> + qid = make_kqid_projid(projid);
> + dquot = dqget(sb, qid);
> + if (!dquot)
> + return -ESRCH;
> + spin_lock(&dq_data_lock);
> +
> + limit = dquot->dq_dqb.dqb_bsoftlimit ?
> + dquot->dq_dqb.dqb_bsoftlimit :
> + dquot->dq_dqb.dqb_bhardlimit;
> + if (limit && buf->f_blocks * buf->f_bsize > limit) {
> + curblock = dquot->dq_dqb.dqb_curspace / buf->f_bsize;
> + buf->f_blocks = limit / buf->f_bsize;
> + buf->f_bfree = buf->f_bavail =
> + (buf->f_blocks > curblock) ?
> + (buf->f_blocks - curblock) : 0;
> + }
> +
> + limit = dquot->dq_dqb.dqb_isoftlimit ?
> + dquot->dq_dqb.dqb_isoftlimit :
> + dquot->dq_dqb.dqb_ihardlimit;
> + if (limit && buf->f_files > limit) {
> + buf->f_files = limit;
> + buf->f_ffree =
> + (buf->f_files > dquot->dq_dqb.dqb_curinodes) ?
> + (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
> + }
> +
> + spin_unlock(&dq_data_lock);
> + dqput(dquot);
> + return 0;
> +}
> +
> static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
> {
> struct super_block *sb = dentry->d_sb;
> @@ -5038,6 +5103,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
> ext4_fsblk_t overhead = 0, resv_blocks;
> u64 fsid;
> s64 bfree;
> + struct inode *inode = dentry->d_inode;
> resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters));
>
> if (!test_opt(sb, MINIX_DF))
> @@ -5062,6 +5128,9 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
> buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
> buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
>
> + if (ext4_test_inode_flag(inode, EXT4_INODE_PROJINHERIT) &&
> + sb_has_quota_limits_enabled(sb, PRJQUOTA))
> + ext4_statfs_project(sb, EXT4_I(inode)->i_projid, buf);
> return 0;
> }
>
> @@ -5142,7 +5211,9 @@ static int ext4_mark_dquot_dirty(struct dquot *dquot)
>
> /* Are we journaling quotas? */
> if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) ||
> - sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
> + sbi->s_qf_names[USRQUOTA] ||
> + sbi->s_qf_names[GRPQUOTA] ||
> + sbi->s_qf_names[PRJQUOTA]) {
> dquot_mark_dquot_dirty(dquot);
> return ext4_write_dquot(dquot);
> } else {
> @@ -5226,7 +5297,8 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
> struct inode *qf_inode;
> unsigned long qf_inums[EXT4_MAXQUOTAS] = {
> le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
> - le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
> + le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
> + le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
> };
>
> BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA));
> @@ -5254,7 +5326,8 @@ static int ext4_enable_quotas(struct super_block *sb)
> int type, err = 0;
> unsigned long qf_inums[EXT4_MAXQUOTAS] = {
> le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
> - le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
> + le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
> + le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
> };
>
> sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
> --
> 1.7.1
>
--
Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [v6 4/4] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
2014-11-08 17:43 ` [v6 4/4] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support Li Xi
2014-11-10 0:05 ` Dave Chinner
@ 2014-11-11 21:58 ` Dave Chinner
1 sibling, 0 replies; 14+ messages in thread
From: Dave Chinner @ 2014-11-11 21:58 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel, linux-ext4, linux-api, tytso, adilger, jack, viro,
hch, dmonakhov
On Sun, Nov 09, 2014 at 01:43:39AM +0800, Li Xi wrote:
> This patch adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR ioctl interface
> support for ext4. The interface is kept consistent with
> XFS_IOC_FSGETXATTR/XFS_IOC_FSGETXATTR.
I missed somethignthe first time around, and it's to do with
fsx_flags field and what ext4 is putting in it....
> @@ -617,7 +713,45 @@ resizefs_out:
> }
> case EXT4_IOC_PRECACHE_EXTENTS:
> return ext4_ext_precache(inode);
> + case EXT4_IOC_FSGETXATTR:
> + {
> + struct fsxattr fa;
> +
> + memset(&fa, 0, sizeof(struct fsxattr));
> +
> + ext4_get_inode_flags(ei);
> + fa.fsx_xflags = ei->i_flags & EXT4_FL_USER_VISIBLE;
You're putting ext4 inode flags in this field. That's not right -
the flags that are defined for this field are the XFS_XFLAGS_*
fields, and you need to translate between the ext4 flags and the
existing falg definitions. Any falg definitions that don't already
exist that ext4 needs to support need to be added to the XFS_XFLAGS
definitions.
i.e. this is not a field that has flags defined by ext4 - the
flags must be the same across all filesystems that implement it, and
that means ext4 must use the existing definitions where they already
exist.
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2014-11-11 21:58 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-08 17:43 [v6 0/4] ext4: add project quota support Li Xi
[not found] ` <1415468619-31851-1-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-08 17:43 ` [v6 1/4] vfs: adds general codes to enforces project quota limits Li Xi
[not found] ` <1415468619-31851-2-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-11 20:27 ` Jan Kara
2014-11-08 17:43 ` [v6 2/4] ext4: adds project ID support Li Xi
2014-11-10 22:21 ` Andreas Dilger
[not found] ` <1415468619-31851-3-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-11 4:26 ` Theodore Ts'o
2014-11-11 7:34 ` Li Xi
2014-11-11 20:23 ` Jan Kara
2014-11-11 20:31 ` Jan Kara
2014-11-08 17:43 ` [v6 3/4] ext4: adds project quota support Li Xi
[not found] ` <1415468619-31851-4-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
2014-11-11 20:34 ` Jan Kara
2014-11-08 17:43 ` [v6 4/4] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support Li Xi
2014-11-10 0:05 ` Dave Chinner
2014-11-11 21:58 ` Dave Chinner
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).