Skip to contentSkip to conversation

e2fsprogs: project quota

RFC PATCH New Konstantin Khlebnikov 1 participant 5 messages Mar 13, 2015

lore
Share & tools
lore
#0 lore raw

cover e2fsprogs: project quota

Projects quota allows to enforce disk quota for several subtrees or even individual files on the filesystem. Each inode is marked with project-id (independently from uid and gid) and accounted into corresponding project quota. New files inherits project id from directory where they are created.

This patchset adds required support into mkfs, fsck, tune2fs, debugfs, chattr and lsattr.

All patches are available at github:
https://github.com/koct9i/linux --branch project
https://github.com/koct9i/e2fsprogs --branch project
https://github.com/koct9i/quota-tools --branch project

Ext4 layout
-----------

Project id introduce ro-compatible feature 'project'.

Inode project id is stored in place of obsolete field 'i_faddr' (that trick was suggested by Darrick J. Wong in previous discussions of project quota). Linux never used that field and fsck checks that it contains zero.

Quota information is stored in reserved/special inode №11. For symmetry with other quotas inode number is stored in superblock.

By default only 10 inodes are reserved for special usage.
After this patch mkfs will reserve 20 inodes if feature project is enabled. I've add option to resize2fs to reserve more inodes in existing filestsrem. (See patchset [PATCH RFC v1 0/4] e2fsprogs: reserve more special inodes)

For now project quota supports only modern 'hidden' journaled mode.

---

Konstantin Khlebnikov (4):
e2fsprogs: introduce project id feature
e2fsprogs: add project quota support
e2fsprogs: add tests for project quota
e2fsprogs: add project id into lsattr and chattr

 debugfs/debugfs.c           |   40 ++++++++---
 debugfs/quota.c             |    8 +-
 debugfs/set_fields.c        |    4 +
 e2fsck/pass1.c              |   14 +++-
 e2fsck/pass2.c              |    3 +
 e2fsck/quota.c              |   11 +++
 e2fsck/unix.c               |   25 ++++---
 lib/e2p/Makefile.in         |    5 +
 lib/e2p/e2p.h               |    2 +
 lib/e2p/feature.c           |    2 +
 lib/e2p/ls.c                |    3 +
 lib/e2p/project.c           |   55 +++++++++++++++
 lib/ext2fs/ext2_fs.h        |   19 ++++-
 lib/ext2fs/ext2fs.h         |    3 +
 lib/ext2fs/swapfs.c         |    3 +
 lib/ext2fs/tst_inode_size.c |    2 -
 lib/ext2fs/tst_super_size.c |    3 +
 lib/quota/mkquota.c         |   42 ++++++++++--
 lib/quota/quotaio.c         |   23 ++++--
 lib/quota/quotaio.h         |    7 +-
 misc/chattr.1.in            |    7 ++
 misc/chattr.c               |   34 +++++++++
 misc/ext4.5.in              |    7 ++
 misc/lsattr.1.in            |    5 +
 misc/lsattr.c               |   19 +++++
 misc/mke2fs.8.in            |    5 +
 misc/mke2fs.c               |   26 ++++++-
 misc/tune2fs.8.in           |    9 ++
 misc/tune2fs.c              |   77 +++++++++++++++++++--
 tests/m_project/expect.1    |  156 +++++++++++++++++++++++++++++++++++++++++++
 tests/m_project/script      |    7 ++
 tests/t_project_1on/expect  |   66 ++++++++++++++++++
 tests/t_project_1on/name    |    1 
 tests/t_project_1on/script  |   68 +++++++++++++++++++
 tests/t_project_2off/expect |   78 ++++++++++++++++++++++
 tests/t_project_2off/name   |    1 
 tests/t_project_2off/script |   54 +++++++++++++++
 37 files changed, 821 insertions(+), 73 deletions(-)
 create mode 100644 lib/e2p/project.c
 create mode 100644 tests/m_project/expect.1
 create mode 100644 tests/m_project/script
 create mode 100644 tests/t_project_1on/expect
 create mode 100644 tests/t_project_1on/name
 create mode 100644 tests/t_project_1on/script
 create mode 100644 tests/t_project_2off/expect
 create mode 100644 tests/t_project_2off/name
 create mode 100644 tests/t_project_2off/script

--
Signature
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#1 lore raw

RFC PATCH 1/4 e2fsprogs: introduce project id feature

* add feature EXT4_FEATURE_RO_COMPAT_PROJECT
* reuse obsolete inode field i_faddr as i_project
* add field s_prj_quota_inum into superblock for project quota inode

---
 debugfs/debugfs.c           |   40 ++++++++++++++++++++++++++++------------
 debugfs/set_fields.c        |    4 +++-
 e2fsck/pass1.c              |    5 ++++-
 e2fsck/pass2.c              |    3 ++-
 lib/e2p/feature.c           |    2 ++
 lib/e2p/ls.c                |    3 +++
 lib/ext2fs/ext2_fs.h        |    9 ++++++---
 lib/ext2fs/ext2fs.h         |    3 ++-
 lib/ext2fs/swapfs.c         |    3 ++-
 lib/ext2fs/tst_inode_size.c |    2 +-
 lib/ext2fs/tst_super_size.c |    3 ++-
 misc/mke2fs.c               |    3 ++-
 misc/tune2fs.c              |   28 ++++++++++++++++++++++++++--
 13 files changed, 83 insertions(+), 25 deletions(-)
debugfs/debugfs.c +28 -12
index fe57366ffa98..066d9a7825f2 100644
@@ -713,7 +713,7 @@ void internal_dump_inode(FILE *out, const char *prefix,
 			 int do_dump_blocks)
 {
 	const char *i_type;
-	char frag, fsize;
+	struct ext2_super_block *sb = current_fs->super;
 	int os = current_fs->super->s_creator_os;
 	struct ext2_inode_large *large_inode;
 	int is_large_inode = 0;
@@ -741,8 +741,11 @@ void internal_dump_inode(FILE *out, const char *prefix,
 		fprintf(out, "%sGeneration: %u    Version: 0x%08x\n", prefix,
 			inode->i_generation, inode->osd1.linux1.l_i_version);
 	}
-	fprintf(out, "%sUser: %5d   Group: %5d   Size: ",
+	fprintf(out, "%sUser: %5d   Group: %5d   ",
 		prefix, inode_uid(*inode), inode_gid(*inode));
+	if (EXT2_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
+		fprintf(out, "Project: %5d   ", large_inode->i_project);
+	fprintf(out, "Size: ");
 	if (LINUX_S_ISREG(inode->i_mode))
 		fprintf(out, "%llu\n", EXT2_I_SIZE(inode));
 	else
@@ -768,16 +771,22 @@ void internal_dump_inode(FILE *out, const char *prefix,
 	else
 		fprintf(out, "%sLinks: %d   Blockcount: %u\n",
 			prefix, inode->i_links_count, inode->i_blocks);
-	switch (os) {
-	    case EXT2_OS_HURD:
-		frag = inode->osd2.hurd2.h_i_frag;
-		fsize = inode->osd2.hurd2.h_i_fsize;
-		break;
-	    default:
-		frag = fsize = 0;
+
+	if (!EXT2_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+		char frag, fsize;
+
+		switch (os) {
+		case EXT2_OS_HURD:
+			frag = inode->osd2.hurd2.h_i_frag;
+			fsize = inode->osd2.hurd2.h_i_fsize;
+			break;
+		default:
+			frag = fsize = 0;
+		}
+		fprintf(out, "%sFragment:  Address: %d    Number: %d    Size: %d\n",
+				prefix, inode->i_faddr, frag, fsize);
 	}
-	fprintf(out, "%sFragment:  Address: %d    Number: %d    Size: %d\n",
-		prefix, inode->i_faddr, frag, fsize);
+
 	if (is_large_inode && large_inode->i_extra_isize >= 24) {
 		fprintf(out, "%s ctime: 0x%08x:%08x -- %s", prefix,
 			inode->i_ctime, large_inode->i_ctime_extra,
@@ -1256,7 +1265,14 @@ void do_modify_inode(int argc, char *argv[])
 		modify_u32(argv[0], "Translator Block",
 			    decimal_format, &inode.osd1.hurd1.h_i_translator);
 
-	modify_u32(argv[0], "Fragment address", decimal_format, &inode.i_faddr);
+	if (EXT2_HAS_RO_COMPAT_FEATURE(current_fs->super,
+				EXT4_FEATURE_RO_COMPAT_PROJECT))
+		modify_u32(argv[0], "Project ID", decimal_format,
+				&inode.i_project);
+	else
+		modify_u32(argv[0], "Fragment address", decimal_format,
+				&inode.i_faddr);
+
 	switch (os) {
 	    case EXT2_OS_HURD:
 		frag = &inode.osd2.hurd2.h_i_frag;
debugfs/set_fields.c +3 -1
index 37fd5ec0e6e8..81689bbb6611 100644
@@ -167,6 +167,7 @@ static struct field_set_info super_fields[] = {
 	{ "last_error_line", &set_sb.s_last_error_line, NULL, 4, parse_uint },
 	{ "encrypt_algos", &set_sb.s_encrypt_algos, NULL, 1, parse_uint,
 	  FLAG_ARRAY, 4 },
+	{ "prj_quota_inum", &set_sb.s_prj_quota_inum, NULL, 4, parse_uint },
 	{ 0, 0, 0, 0 }
 };
 
@@ -200,7 +201,8 @@ static struct field_set_info inode_fields[] = {
 	{ "file_acl", &set_inode.i_file_acl, 
 		&set_inode.osd2.linux2.l_i_file_acl_high, 6, parse_uint },
 	{ "dir_acl", &set_inode.i_dir_acl, NULL, 4, parse_uint, FLAG_ALIAS },
-	{ "faddr", &set_inode.i_faddr, NULL, 4, parse_uint },
+	{ "project", &set_inode.i_project, NULL, 4, parse_uint },
+	{ "faddr", &set_inode.i_faddr, NULL, 4, parse_uint, FLAG_ALIAS },
 	{ "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint, FLAG_ALIAS },
 	{ "fsize", &set_inode.osd2.hurd2.h_i_fsize, NULL, 1, parse_uint },
 	{ "checksum", &set_inode.osd2.linux2.l_i_checksum_lo, 
e2fsck/pass1.c +4 -1
index 319d23b84938..b5ac4a8587eb 100644
@@ -1567,7 +1567,10 @@ void e2fsck_pass1(e2fsck_t ctx)
 			frag = fsize = 0;
 		}
 
-		if (inode->i_faddr || frag || fsize ||
+		if (inode->i_faddr && !EXT2_HAS_RO_COMPAT_FEATURE(sb,
+					EXT4_FEATURE_RO_COMPAT_PROJECT))
+			mark_inode_bad(ctx, ino);
+		if (frag || fsize ||
 		    (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
 			mark_inode_bad(ctx, ino);
 		if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
e2fsck/pass2.c +2 -1
index 94665c6ed3dc..26af55c9d4dd 100644
@@ -1746,7 +1746,8 @@ int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
 		problem = 0;
 	}
 
-	if (inode.i_faddr) {
+	if (inode.i_faddr && !EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+				EXT4_FEATURE_RO_COMPAT_PROJECT)) {
 		if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
 			inode.i_faddr = 0;
 			inode_modified++;
lib/e2p/feature.c +2 -0
index 73884f2cf5bf..5b155a90252a 100644
@@ -70,6 +70,8 @@ static struct feature feature_list[] = {
 			"replica" },
 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY,
 			"read-only" },
+	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_PROJECT,
+			"project" },
 
 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
 			"compression" },
lib/e2p/ls.c +3 -0
index a7ea38a44136..182de2245c72 100644
@@ -440,6 +440,9 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
 	if (sb->s_grp_quota_inum)
 		fprintf(f, "Group quota inode:        %u\n",
 			sb->s_grp_quota_inum);
+	if (sb->s_prj_quota_inum)
+		fprintf(f, "Project quota inode:      %u\n",
+			sb->s_prj_quota_inum);
 
 	if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
 		fprintf(f, "Checksum type:            %s\n",
lib/ext2fs/ext2_fs.h +6 -3
index 6715d4e04a9a..5ff835e60657 100644
@@ -398,7 +398,7 @@ struct ext2_inode {
 	__u32	i_generation;	/* File version (for NFS) */
 	__u32	i_file_acl;	/* File ACL */
 	__u32	i_size_high;	/* Formerly i_dir_acl, directory ACL */
-	__u32	i_faddr;	/* Fragment address */
+	__u32	i_project;	/* Formerly i_faddr, fragment address */
 	union {
 		struct {
 			__u16	l_i_blocks_hi;
@@ -446,7 +446,7 @@ struct ext2_inode_large {
 	__u32	i_generation;	/* File version (for NFS) */
 	__u32	i_file_acl;	/* File ACL */
 	__u32	i_size_high;	/* Formerly i_dir_acl, directory ACL */
-	__u32	i_faddr;	/* Fragment address */
+	__u32	i_project;	/* Formerly i_faddr, fragment address */
 	union {
 		struct {
 			__u16	l_i_blocks_hi;
@@ -480,6 +480,7 @@ struct ext2_inode_large {
 	 EXT2_GOOD_OLD_INODE_SIZE)
 
 #define i_dir_acl	i_size_high
+#define i_faddr		i_project
 
 #define i_checksum_lo	osd2.linux2.l_i_checksum_lo
 
@@ -683,7 +684,8 @@ struct ext2_super_block {
 	__u32	s_overhead_blocks;	/* overhead blocks/clusters in fs */
 	__u32	s_backup_bgs[2];	/* If sparse_super2 enabled */
 	__u8	s_encrypt_algos[4];	/* Encryption algorithms in use  */
-	__u32   s_reserved[105];        /* Padding to the end of the block */
+	__u32	s_prj_quota_inum;	/* inode number of project quota file */
+	__u32   s_reserved[104];	/* Padding to the end of the block */
 	__u32	s_checksum;		/* crc32c(superblock) */
 };
 
@@ -755,6 +757,7 @@ struct ext2_super_block {
 #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM	0x0400
 #define EXT4_FEATURE_RO_COMPAT_REPLICA		0x0800
 #define EXT4_FEATURE_RO_COMPAT_READONLY		0x1000
+#define EXT4_FEATURE_RO_COMPAT_PROJECT		0x2000 /* Project ID / Quota */
 
 
 #define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001
lib/ext2fs/ext2fs.h +2 -1
index d75dd7654c34..ca84c70fc7c1 100644
@@ -610,7 +610,8 @@ typedef struct ext2_icount *ext2_icount_t;
 					 EXT4_FEATURE_RO_COMPAT_BIGALLOC|\
 					 EXT4_LIB_RO_COMPAT_QUOTA|\
 					 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\
-					 EXT4_FEATURE_RO_COMPAT_READONLY)
+					 EXT4_FEATURE_RO_COMPAT_READONLY|\
+					 EXT4_FEATURE_RO_COMPAT_PROJECT)
 
 /*
  * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
lib/ext2fs/swapfs.c +2 -1
index ee7a45591598..98910e6d1faf 100644
@@ -82,6 +82,7 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
 	sb->s_usr_quota_inum = ext2fs_swab32(sb->s_usr_quota_inum);
 	sb->s_grp_quota_inum = ext2fs_swab32(sb->s_grp_quota_inum);
 	sb->s_overhead_blocks = ext2fs_swab32(sb->s_overhead_blocks);
+	sb->s_prj_quota_inum = ext2fs_swab32(sb->s_prj_quota_inum);
 	sb->s_checksum = ext2fs_swab32(sb->s_checksum);
 
 	for (i=0; i < 4; i++)
@@ -257,7 +258,7 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 			t->i_block[i] = f->i_block[i];
 	}
 	t->i_generation = ext2fs_swab32(f->i_generation);
-	t->i_faddr = ext2fs_swab32(f->i_faddr);
+	t->i_project = ext2fs_swab32(f->i_project);
 
 	switch (fs->super->s_creator_os) {
 	case EXT2_OS_LINUX:
lib/ext2fs/tst_inode_size.c +1 -1
index e20ec981111a..384d1c2ba946 100644
@@ -65,7 +65,7 @@ int main(int argc, char **argv)
 	check_field(i_generation, 4);
 	check_field(i_file_acl, 4);
 	check_field(i_size_high, 4);
-	check_field(i_faddr, 4);
+	check_field(i_project, 4);
 	check_field(osd2.linux2.l_i_blocks_hi, 2);
 	check_field(osd2.linux2.l_i_file_acl_high, 2);
 	check_field(osd2.linux2.l_i_uid_high, 2);
lib/ext2fs/tst_super_size.c +2 -1
index f6c74f75db34..947fb2a632cd 100644
@@ -137,7 +137,8 @@ int main(int argc, char **argv)
 	check_field(s_overhead_blocks, 4);
 	check_field(s_backup_bgs, 8);
 	check_field(s_encrypt_algos, 4);
-	check_field(s_reserved, 105 * 4);
+	check_field(s_prj_quota_inum, 4);
+	check_field(s_reserved, 104 * 4);
 	check_field(s_checksum, 4);
 	do_field("Superblock end", 0, 0, cur_offset, 1024);
 #endif
misc/mke2fs.c +2 -1
index 742f81694b84..5427305b748d 100644
@@ -1107,7 +1107,8 @@ static __u32 ok_features[3] = {
 #ifdef CONFIG_QUOTA
 		EXT4_FEATURE_RO_COMPAT_QUOTA|
 #endif
-		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
+		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM |
+		EXT4_FEATURE_RO_COMPAT_PROJECT
 };
 
 
misc/tune2fs.c +26 -2
index 550932d67949..0410d1c11539 100644
@@ -161,7 +161,8 @@ static __u32 ok_features[3] = {
 		EXT4_FEATURE_RO_COMPAT_QUOTA |
 #endif
 		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM |
-		EXT4_FEATURE_RO_COMPAT_READONLY
+		EXT4_FEATURE_RO_COMPAT_READONLY |
+		EXT4_FEATURE_RO_COMPAT_PROJECT
 };
 
 static __u32 clear_ok_features[3] = {
@@ -184,7 +185,8 @@ static __u32 clear_ok_features[3] = {
 		EXT4_FEATURE_RO_COMPAT_QUOTA |
 #endif
 		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM |
-		EXT4_FEATURE_RO_COMPAT_READONLY
+		EXT4_FEATURE_RO_COMPAT_READONLY |
+		EXT4_FEATURE_RO_COMPAT_PROJECT
 };
 
 /**
@@ -1303,6 +1305,28 @@ mmp_error:
 		grpquota = QOPT_DISABLE;
 	}
 
+	if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT,
+				EXT4_FEATURE_RO_COMPAT_PROJECT) &&
+	    (mount_flags & EXT2_MF_MOUNTED) &&
+	    !(mount_flags & EXT2_MF_READONLY)) {
+		fputs(_("The project feature may only be "
+			"changed when the filesystem is\n"
+			"unmounted or mounted read-only.\n"), stderr);
+		return 1;
+	}
+
+	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
+				EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+		sb->s_feature_ro_compat |= EXT4_FEATURE_RO_COMPAT_PROJECT;
+	}
+
+	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+				EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+		sb->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_PROJECT;
+		/* fsck will reset i_project (i_faddr) for us. */
+		request_fsck_afterwards(fs);
+	}
+
 	if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
 	    (sb->s_feature_compat || sb->s_feature_ro_compat ||
 	     sb->s_feature_incompat))
#2 lore raw

RFC PATCH 2/4 e2fsprogs: add project quota support

In reply to Konstantin Khlebnikov

This patch adds third quota type: project quota.

For symmetry with other quotas inode number is stored in superblock but for now project quota supports only modern 'hidden' journal mode in inode 11. (non-hidden mode might be useful because if can work without reserved inode)

When feature 'project' is enabled mke2fs automatically enables project quota and reserves first 20 inodes for special usage (instead of default 10). Changing that reservation unconditionally breaks too much tests where inode numbers are present in expected output or even hardcoded: for example in "tst_inline_data".

---
 debugfs/quota.c      |    8 +++++---
 e2fsck/pass1.c       |    9 ++++++---
 e2fsck/quota.c       |   11 +++++++++++
 e2fsck/unix.c        |   25 ++++++++++++++++---------
 lib/ext2fs/ext2_fs.h |    5 +++++
 lib/quota/mkquota.c  |   42 ++++++++++++++++++++++++++++++++++++------
 lib/quota/quotaio.c  |   23 ++++++++++++++---------
 lib/quota/quotaio.h  |    7 +++++--
 misc/ext4.5.in       |    7 +++++++
 misc/mke2fs.8.in     |    5 ++++-
 misc/mke2fs.c        |   23 +++++++++++++++++++++--
 misc/tune2fs.8.in    |    9 +++++++++
 misc/tune2fs.c       |   49 ++++++++++++++++++++++++++++++++++++++++++++-----
 13 files changed, 183 insertions(+), 40 deletions(-)
debugfs/quota.c +5 -3
index 9612f6420cb4..c4449e2d68dd 100644
@@ -25,7 +25,7 @@ extern char *optarg;
 
 #include "debugfs.h"
 
-const char *quota_type[] = { "user", "group", NULL };
+const char *quota_type[] = { "user", "group", "project", NULL };
 
 static int load_quota_ctx(char *progname)
 {
@@ -121,7 +121,8 @@ void do_list_quota(int argc, char *argv[])
 		return;
 
 	printf("%8s   %8s %8s %8s    %8s %8s %8s\n",
-	       (type == 0) ? "user id" : "group id",
+	       (type == USRQUOTA) ? "user id" :
+	       (type == GRPQUOTA) ? "group id" : "project",
 	       "blocks", "quota", "limit", "inodes", "quota", "limit");
 	qh = current_qctx->quota_file[type];
 	retval = qh->qh_ops->scan_dquots(qh, list_quota_callback, NULL);
@@ -155,7 +156,8 @@ void do_get_quota(int argc, char *argv[])
 		return;
 
 	printf("%8s   %8s %8s %8s    %8s %8s %8s\n",
-	       (type == 0) ? "user id" : "group id",
+	       (type == USRQUOTA) ? "user id" :
+	       (type == GRPQUOTA) ? "group id" : "project",
 	       "blocks", "quota", "limit", "inodes", "quota", "limit");
 
 	qh = current_qctx->quota_file[type];
e2fsck/pass1.c +6 -3
index b5ac4a8587eb..701af354fb24 100644
@@ -1437,12 +1437,15 @@ void e2fsck_pass1(e2fsck_t ctx)
 				failed_csum = 0;
 			}
 		} else if ((ino == EXT4_USR_QUOTA_INO) ||
-			   (ino == EXT4_GRP_QUOTA_INO)) {
+			   (ino == EXT4_GRP_QUOTA_INO) ||
+			   (ino < EXT2_FIRST_INODE(fs->super) &&
+			    ino == EXT4_PRJ_QUOTA_INO)) {
 			ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
 			if ((fs->super->s_feature_ro_compat &
 					EXT4_FEATURE_RO_COMPAT_QUOTA) &&
-			    ((fs->super->s_usr_quota_inum == ino) ||
-			     (fs->super->s_grp_quota_inum == ino))) {
+			    ((sb->s_usr_quota_inum == ino) ||
+			     (sb->s_grp_quota_inum == ino) ||
+			     (sb->s_prj_quota_inum == ino))) {
 				if (!LINUX_S_ISREG(inode->i_mode) &&
 				    fix_problem(ctx, PR_1_QUOTA_BAD_MODE,
 							&pctx)) {
e2fsck/quota.c +11 -0
index c6bbb9afc47f..86a0031e8139 100644
@@ -88,5 +88,16 @@ void e2fsck_hide_quota(e2fsck_t ctx)
 		sb->s_grp_quota_inum = EXT4_GRP_QUOTA_INO;
 	}
 
+	pctx.ino = sb->s_prj_quota_inum;
+	if ((sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_PROJECT) &&
+	    sb->s_prj_quota_inum &&
+	    (sb->s_prj_quota_inum != EXT4_PRJ_QUOTA_INO) &&
+	    (sb->s_first_ino > EXT4_PRJ_QUOTA_INO) &&
+	    fix_problem(ctx, PR_0_HIDE_QUOTA, &pctx)) {
+		move_quota_inode(fs, sb->s_prj_quota_inum, EXT4_PRJ_QUOTA_INO,
+				 PRJQUOTA);
+		sb->s_prj_quota_inum = EXT4_PRJ_QUOTA_INO;
+	}
+
 	return;
 }
e2fsck/unix.c +16 -9
index e6291367db39..5b655502afd1 100644
@@ -1636,14 +1636,20 @@ print_unsupp_features:
 		journal_size = -1;
 
 	if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_QUOTA) {
-		/* Quotas were enabled. Do quota accounting during fsck. */
-		if ((sb->s_usr_quota_inum && sb->s_grp_quota_inum) ||
-		    (!sb->s_usr_quota_inum && !sb->s_grp_quota_inum))
-			qtype = -1;
-		else
-			qtype = sb->s_usr_quota_inum ? USRQUOTA : GRPQUOTA;
-
-		quota_init_context(&ctx->qctx, ctx->fs, qtype);
+		/*
+		 * Quotas were enabled. Do quota accounting during fsck.
+		 * If no quotas in-use then initialize all supported types.
+		 */
+		qtype = -2;
+		if (sb->s_usr_quota_inum)
+			qtype = USRQUOTA;
+		if (sb->s_grp_quota_inum)
+			qtype = (qtype == -2) ? GRPQUOTA : -1;
+		if (sb->s_prj_quota_inum && EXT2_HAS_RO_COMPAT_FEATURE(sb,
+						EXT4_FEATURE_RO_COMPAT_PROJECT))
+			qtype = (qtype == -2) ? PRJQUOTA : -1;
+
+		quota_init_context(&ctx->qctx, ctx->fs, qtype < 0 ? -1 : qtype);
 	}
 
 	run_result = e2fsck_run(ctx);
@@ -1682,7 +1688,8 @@ no_journal:
 	if (ctx->qctx) {
 		int i, needs_writeout;
 		for (i = 0; i < MAXQUOTAS; i++) {
-			if (qtype != -1 && qtype != i)
+			if ((qtype == -1 && !quota_get_sb_inum(fs, i)) ||
+			    (qtype >= 0 && qtype != i))
 				continue;
 			needs_writeout = 0;
 			pctx.num = i;
lib/ext2fs/ext2_fs.h +5 -0
index 5ff835e60657..77cde1bc009f 100644
@@ -56,6 +56,11 @@
 /* First non-reserved inode for old ext2 filesystems */
 #define EXT2_GOOD_OLD_FIRST_INO	11
 
+#define EXT4_PRJ_QUOTA_INO	11	/* Project quota inode */
+
+/* Default first non-reserved inode for new filesystems */
+#define EXT4_DEFAULT_FIRST_INO	21
+
 /*
  * The second extended file system magic number
  */
lib/quota/mkquota.c +36 -6

74 lines not on this page · raw message

lib/quota/quotaio.c +14 -9
index c7e5f87b5a1b..bc055c8ea91f 100644
@@ -19,7 +19,7 @@
 #include "common.h"
 #include "quotaio.h"
 
-static const char * const extensions[MAXQUOTAS] = {"user", "group"};
+static const char * const extensions[MAXQUOTAS] = {"user", "group", "project"};
 static const char * const basenames[] = {
 	"",		/* undefined */
 	"quota",	/* QFMT_VFS_OLD */
@@ -118,7 +118,8 @@ errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino)
 	if ((err = ext2fs_read_inode(fs, ino, &inode)))
 		return err;
 
-	if ((ino == EXT4_USR_QUOTA_INO) || (ino == EXT4_GRP_QUOTA_INO)) {
+	if ((ino == EXT4_USR_QUOTA_INO) || (ino == EXT4_GRP_QUOTA_INO) ||
+	    (ino == EXT4_PRJ_QUOTA_INO)) {
 		inode.i_dtime = fs->now ? fs->now : time(0);
 		if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
 			return 0;
@@ -215,12 +216,8 @@ errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h,
 	if (err)
 		return err;
 
-	if (qf_ino == 0) {
-		if (type == USRQUOTA)
-			qf_ino = fs->super->s_usr_quota_inum;
-		else
-			qf_ino = fs->super->s_grp_quota_inum;
-	}
+	if (qf_ino == 0)
+		qf_ino = quota_get_sb_inum(fs, type);
 
 	log_debug("Opening quota ino=%lu, type=%d", qf_ino, type);
 	err = ext2fs_file_open(fs, qf_ino, flags, &e2_file);
@@ -318,19 +315,27 @@ errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, in
 {
 	ext2_file_t e2_file;
 	int err;
-	unsigned long qf_inum;
+	ext2_ino_t qf_inum;
 
 	if (fmt == -1)
 		fmt = QFMT_VFS_V1;
 
 	h->qh_qf.fs = fs;
+
 	if (type == USRQUOTA)
 		qf_inum = EXT4_USR_QUOTA_INO;
 	else if (type == GRPQUOTA)
 		qf_inum = EXT4_GRP_QUOTA_INO;
+	else if (type == PRJQUOTA)
+		qf_inum = EXT4_PRJ_QUOTA_INO;
 	else
 		return -1;
 
+	if (qf_inum >= EXT2_FIRST_INO(fs->super)) {
+		log_err("quota inode is not special");
+		return EXT2_ET_BAD_INODE_NUM;
+	}
+
 	err = ext2fs_read_bitmaps(fs);
 	if (err)
 		goto out_err;
lib/quota/quotaio.h +5 -2
index 7ca7830e8264..04bec25bae99 100644
@@ -44,9 +44,10 @@
 
 typedef int64_t qsize_t;	/* Type in which we store size limitations */
 
-#define MAXQUOTAS 2
+#define MAXQUOTAS 3
 #define USRQUOTA 0
 #define GRPQUOTA 1
+#define PRJQUOTA 2
 
 typedef struct quota_ctx *quota_ctx_t;
 
@@ -61,7 +62,8 @@ struct quota_ctx {
  */
 #define INITQMAGICS {\
 	0xd9c01f11,	/* USRQUOTA */\
-	0xd9c01927	/* GRPQUOTA */\
+	0xd9c01927,	/* GRPQUOTA */\
+	0xd9c03f14,	/* PRJQUOTA */\
 }
 
 /* Size of blocks in which are counted size limits in generic utility parts */
@@ -216,6 +218,7 @@ void quota_release_context(quota_ctx_t *qctx);
 
 errcode_t quota_remove_inode(ext2_filsys fs, int qtype);
 int quota_file_exists(ext2_filsys fs, int qtype, int fmt);
+ext2_ino_t quota_get_sb_inum(ext2_filsys fs, int qtype);
 void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype);
 errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype,
 				   int *usage_inconsistent);
misc/ext4.5.in +7 -0
index 19302a7297dd..806b30682638 100644
@@ -253,6 +253,13 @@ the file system using
 and it also speeds up the time required for
 .BR mke2fs (8)
 to create the file system.
+.TP
+.B project
+.br
+This filesystem feature adds third identificator to inode - "project ID".
+Projects provides mechanism for aggregating subtrees or individual files
+scattered across filesystem and enforcing disk quotas for them regardless
+of users and groups who own them.
 .RE
 .SH MOUNT OPTIONS
 This section describes mount options which are specific to ext2, ext3,
misc/mke2fs.8.in +4 -1
index d7cafd65ba6f..53055ff033a2 100644
@@ -379,11 +379,14 @@ command-line option to
 .BR resize2fs (8).
 @[email protected]
 @[email protected] quotatype
-@QUOTA_MAN_COMMENT@Specify which quota type ('usr' or 'grp') is to be
+@QUOTA_MAN_COMMENT@Specify which quota type ('usr', 'grp' or 'prj') is to be
 @QUOTA_MAN_COMMENT@initialized. This option has effect only if the
 @[email protected] quota
 @QUOTA_MAN_COMMENT@feature is set. Without this extended option, the default
 @QUOTA_MAN_COMMENT@behavior is to initialize both user and group quotas.
+@QUOTA_MAN_COMMENT@If feature
+@[email protected] project
+@QUOTA_MAN_COMMENT@is set then project quota is also initialized by default.
 .RE
 .TP
 .BI \-f " fragment-size"
misc/mke2fs.c +21 -2
index 5427305b748d..1e1c569af140 100644
@@ -1029,9 +1029,11 @@ static void parse_extended_opts(struct ext2_super_block *param,
 				continue;
 			}
 			if (!strncmp(arg, "usr", 3)) {
-				quotatype = 0;
+				quotatype = USRQUOTA;
 			} else if (!strncmp(arg, "grp", 3)) {
-				quotatype = 1;
+				quotatype = GRPQUOTA;
+			} else if (!strncmp(arg, "prj", 3)) {
+				quotatype = PRJQUOTA;
 			} else {
 				fprintf(stderr,
 					_("Invalid quotatype parameter: %s\n"),
@@ -2449,6 +2451,23 @@ profile_error:
 			fs_param.s_backup_bgs[1] = ~0;
 	}
 
+#ifdef CONFIG_QUOTA
+	if (EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
+				EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+		/* Feature "project" automacally enables project quota */
+		if (!EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
+					EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+			fs_param.s_feature_ro_compat |=
+					EXT4_FEATURE_RO_COMPAT_QUOTA;
+			if (quotatype == -1)
+				quotatype = PRJQUOTA;
+		}
+		/* Reserve special inode for project quota */
+		if (fs_param.s_first_ino <= EXT4_PRJ_QUOTA_INO)
+			fs_param.s_first_ino = EXT4_DEFAULT_FIRST_INO;
+	}
+#endif
+
 	free(fs_type);
 	free(usage_types);
 }
misc/tune2fs.8.in +9 -0
index 9d1df8242baa..3f65b1d4063b 100644
@@ -580,6 +580,12 @@ keep a high watermark for the unused inodes in a filesystem, to reduce
 time.  This first e2fsck run after enabling this feature will take the
 full time, but subsequent e2fsck runs will take only a fraction of the
 original time, depending on how full the file system is.
+.TP
+.B project
+Add project ID to inode.
+@QUOTA_MAN_COMMENT@And project quota if feature
+@[email protected] quota
+@QUOTA_MAN_COMMENT@is enabled.
 .RE
 .IP
 After setting or clearing 
@@ -622,6 +628,9 @@ Sets/clears user quota inode in the superblock.
 .TP
 .BR [^]grpquota
 Sets/clears group quota inode in the superblock.
+.TP
+.BR [^]prjquota
+Sets/clears project quota inode in the superblock.
 .RE
 .TP
 .BI \-T " time-last-checked"
misc/tune2fs.c +44 -5

112 lines not on this page · raw message

#4 lore raw

RFC PATCH 4/4 e2fsprogs: add project id into lsattr and chattr

In reply to Konstantin Khlebnikov

Kernel will provide generic vfs ioctls for project id: FS_IOC_GET/SETPROJECT. This patch adds option '-p' to lsattr and chattr for getting/setting project id.

---
 lib/e2p/Makefile.in  |    5 +++--
 lib/e2p/e2p.h        |    2 ++
 lib/e2p/project.c    |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/ext2_fs.h |    5 +++++
 misc/chattr.1.in     |    7 ++++++
 misc/chattr.c        |   34 ++++++++++++++++++++++++++++---
 misc/lsattr.1.in     |    5 ++++-
 misc/lsattr.c        |   19 +++++++++++++++--
 8 files changed, 124 insertions(+), 8 deletions(-)
 create mode 100644 lib/e2p/project.c
lib/e2p/Makefile.in +3 -2
index e9a635143184..2b7a5e0bb2c5 100644
@@ -19,7 +19,7 @@ all::	e2p.pc
 OBJS=		feature.o fgetflags.o fsetflags.o fgetversion.o fsetversion.o \
 		getflags.o getversion.o hashstr.o iod.o ls.o mntopts.o \
 		parse_num.o pe.o pf.o ps.o setflags.o setversion.o uuid.o \
-		ostype.o percent.o crypto_mode.o
+		ostype.o percent.o crypto_mode.o project.o
 
 SRCS=		$(srcdir)/feature.c $(srcdir)/fgetflags.c \
 		$(srcdir)/fsetflags.c $(srcdir)/fgetversion.c \
@@ -28,7 +28,8 @@ SRCS=		$(srcdir)/feature.c $(srcdir)/fgetflags.c \
 		$(srcdir)/ls.c $(srcdir)/mntopts.c $(srcdir)/parse_num.c \
 		$(srcdir)/pe.c $(srcdir)/pf.c $(srcdir)/ps.c \
 		$(srcdir)/setflags.c $(srcdir)/setversion.c $(srcdir)/uuid.c \
-		$(srcdir)/ostype.c $(srcdir)/percent.c $(srcdir)/crypto_mode.c
+		$(srcdir)/ostype.c $(srcdir)/percent.c $(srcdir)/crypto_mode.c \
+		$(srcdir)/project.c
 HFILES= e2p.h
 
 LIBRARY= libe2p
lib/e2p/e2p.h +2 -0
index 5fa41f46c627..fda72c6adcea 100644
@@ -44,6 +44,8 @@ void print_flags (FILE * f, unsigned long flags, unsigned options);
 void print_fs_state (FILE * f, unsigned short state);
 int setflags (int fd, unsigned long flags);
 int setversion (int fd, unsigned long version);
+int fgetproject(const char *name, unsigned *project);
+int fsetproject(const char *name, unsigned project);
 
 const char *e2p_feature2string(int compat, unsigned int mask);
 const char *e2p_jrnl_feature2string(int compat, unsigned int mask);
lib/e2p/project.c new file +55 -0

55 lines not on this page · raw message

lib/ext2fs/ext2_fs.h +5 -0
index 77cde1bc009f..8ee9566c460b 100644
@@ -376,6 +376,11 @@ struct ext4_new_group_input {
 #define EXT4_IOC_GROUP_ADD		_IOW('f', 8,struct ext4_new_group_input)
 #define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
 
+#ifndef FS_IOC_GETPROJECT
+#define FS_IOC_GETPROJECT		_IOR('f', 20, unsigned)
+#define FS_IOC_SETPROJECT		_IOW('f', 21, unsigned)
+#endif
+
 /*
  * Structure of an inode on the disk
  */
misc/chattr.1.in +7 -0
index 33ef9a20f591..abe0aa496e62 100644
@@ -12,6 +12,10 @@ chattr \- change file attributes on a Linux file system
 .I version
 ]
 [
+.B \-p
+.I project
+]
+[
 .I mode
 ]
 .I files...
@@ -71,6 +75,9 @@ Suppress most error messages.
 .TP
 .BI \-v " version"
 Set the file's version/generation number.
+.TP
+.BI \-p " project"
+Set the file's project id.
 .SH ATTRIBUTES
 A file with the 'a' attribute set can only be open in append mode for writing.
 Only the superuser or a process possessing the CAP_LINUX_IMMUTABLE
misc/chattr.c +31 -3
index f130108c7ec0..ea0ad2e7bd43 100644
@@ -64,6 +64,9 @@ static int set_version;
 
 static unsigned long version;
 
+static int set_project;
+static unsigned project;
+
 static int recursive;
 static int verbose;
 static int silent;
@@ -83,7 +86,7 @@ static unsigned long sf;
 static void usage(void)
 {
 	fprintf(stderr,
-		_("Usage: %s [-RVf] [-+=aAcCdDeijsStTu] [-v version] files...\n"),
+		_("Usage: %s [-RVf] [-+=aAcCdDeijsStTu] [-v version] [-p project] files...\n"),
 		program_name);
 	exit(1);
 }
@@ -159,6 +162,20 @@ static int decode_arg (int * i, int argc, char ** argv)
 				set_version = 1;
 				continue;
 			}
+			if (*p == 'p') {
+				(*i)++;
+				if (*i >= argc)
+					usage();
+				project = strtoul(argv[*i], &tmp, 0);
+				if (*tmp) {
+					com_err (program_name, 0,
+						 _("bad project - %s\n"),
+						 argv[*i]);
+					usage();
+				}
+				set_project = 1;
+				continue;
+			}
 			if ((fl = get_flag(*p)) == 0)
 				usage();
 			rf |= fl;
@@ -248,6 +265,17 @@ static int change_attributes(const char * name)
 			return -1;
 		}
 	}
+	if (set_project) {
+		if (verbose)
+			printf(_("Project of %s set as %u\n"), name, project);
+		if (fsetproject(name, project) == -1) {
+			if (!silent)
+				com_err(program_name, errno,
+					_("while setting project on %s"),
+					name);
+			return -1;
+		}
+	}
 	if (S_ISDIR(st.st_mode) && recursive)
 		return iterate_on_dir (name, chattr_dir_proc, NULL);
 	return 0;
@@ -311,8 +339,8 @@ int main (int argc, char ** argv)
 		fputs("Can't both set and unset same flag.\n", stderr);
 		exit (1);
 	}
-	if (!(add || rem || set || set_version)) {
-		fputs(_("Must use '-v', =, - or +\n"), stderr);
+	if (!(add || rem || set || set_version || set_project)) {
+		fputs(_("Must use '-v', '-p', =, - or +\n"), stderr);
 		exit (1);
 	}
 	if (verbose)
misc/lsattr.1.in +4 -1
index 7798a3444af2..775628b93134 100644
@@ -5,7 +5,7 @@ lsattr \- list file attributes on a Linux second extended file system
 .SH SYNOPSIS
 .B lsattr
 [
-.B \-RVadv
+.B \-RVadvp
 ]
 [
 .I files...
@@ -31,6 +31,9 @@ List directories like other files, rather than listing their contents.
 .TP
 .B \-v
 List the file's version/generation number.
+.TP
+.B \-p
+List the file's project id.
 .SH AUTHOR
 .B lsattr
 was written by Remy Card <[email protected]>.  It is currently being
misc/lsattr.c +17 -2
index e5e59690f493..81b4e9065a56 100644
@@ -60,6 +60,7 @@ static unsigned pf_options;
 static int recursive;
 static int verbose;
 static int generation_opt;
+static int project_opt;
 
 #ifdef _LFS64_LARGEFILE
 #define LSTAT		lstat64
@@ -71,7 +72,7 @@ static int generation_opt;
 
 static void usage(void)
 {
-	fprintf(stderr, _("Usage: %s [-RVadlv] [files...]\n"), program_name);
+	fprintf(stderr, _("Usage: %s [-RVadlvp] [files...]\n"), program_name);
 	exit(1);
 }
 
@@ -94,6 +95,17 @@ static int list_attributes (const char * name)
 		}
 		printf ("%5lu ", generation);
 	}
+	if (project_opt) {
+		unsigned project;
+
+		if (fgetproject(name, &project) == -1) {
+			com_err (program_name, errno,
+				 _("While reading project on %s"),
+				 name);
+			return -1;
+		}
+		printf ("%5u ", project);
+	}
 	if (pf_options & PFOPT_LONG) {
 		printf("%-28s ", name);
 		print_flags(stdout, flags, pf_options);
@@ -171,7 +183,7 @@ int main (int argc, char ** argv)
 #endif
 	if (argc && *argv)
 		program_name = *argv;
-	while ((c = getopt (argc, argv, "RVadlv")) != EOF)
+	while ((c = getopt (argc, argv, "RVadlvp")) != EOF)
 		switch (c)
 		{
 			case 'R':
@@ -192,6 +204,9 @@ int main (int argc, char ** argv)
 			case 'v':
 				generation_opt = 1;
 				break;
+			case 'p':
+				project_opt = 1;
+				break;
 			default:
 				usage();
 		}
#3 lore raw

RFC PATCH 3/4 e2fsprogs: add tests for project quota

In reply to Konstantin Khlebnikov

t_project_1on: enable project quota by resize2fs/tune2fs t_project_2off disable project quota by tune2fs

---
 tests/m_project/expect.1    |  156 +++++++++++++++++++++++++++++++++++++++++++
 tests/m_project/script      |    7 ++
 tests/t_project_1on/expect  |   66 ++++++++++++++++++
 tests/t_project_1on/name    |    1 
 tests/t_project_1on/script  |   68 +++++++++++++++++++
 tests/t_project_2off/expect |   78 ++++++++++++++++++++++
 tests/t_project_2off/name   |    1 
 tests/t_project_2off/script |   54 +++++++++++++++
 8 files changed, 431 insertions(+)
 create mode 100644 tests/m_project/expect.1
 create mode 100644 tests/m_project/script
 create mode 100644 tests/t_project_1on/expect
 create mode 100644 tests/t_project_1on/name
 create mode 100644 tests/t_project_1on/script
 create mode 100644 tests/t_project_2off/expect
 create mode 100644 tests/t_project_2off/name
 create mode 100644 tests/t_project_2off/script
tests/m_project/expect.1 new file +156 -0
new file mode 100644
index 000000000000..e8140f5cc963
@@ -0,0 +1,156 @@
+Creating filesystem with 131072 1k blocks and 32768 inodes
+Superblock backups stored on blocks: 
+	8193, 24577, 40961, 57345, 73729
+
+Allocating group tables:      done                            
+Writing inode tables:      done                            
+Writing superblocks and filesystem accounting information:      done
+
+Filesystem features: ext_attr resize_inode dir_index filetype sparse_super quota project
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 21/32768 files (4.8% non-contiguous), 5697/131072 blocks
+Exit status is 0
+Filesystem volume name:   <none>
+Last mounted on:          <not available>
+Filesystem magic number:  0xEF53
+Filesystem revision #:    1 (dynamic)
+Filesystem features:      ext_attr resize_inode dir_index filetype sparse_super quota project
+Default mount options:    (none)
+Filesystem state:         clean
+Errors behavior:          Continue
+Filesystem OS type:       Linux
+Inode count:              32768
+Block count:              131072
+Reserved block count:     6553
+Free blocks:              125375
+Free inodes:              32747
+First block:              1
+Block size:               1024
+Fragment size:            1024
+Reserved GDT blocks:      256
+Blocks per group:         8192
+Fragments per group:      8192
+Inodes per group:         2048
+Inode blocks per group:   256
+Mount count:              0
+Check interval:           15552000 (6 months)
+Reserved blocks uid:      0
+Reserved blocks gid:      0
+First inode:              21
+Inode size:	          128
+Default directory hash:   half_md4
+Project quota inode:      11
+
+
+Group 0: (Blocks 1-8192)
+  Primary superblock at 1, Group descriptors at 2-2
+  Reserved GDT blocks at 3-258
+  Block bitmap at 259 (+258), Inode bitmap at 260 (+259)
+  Inode table at 261-516 (+260)
+  7656 free blocks, 2027 free inodes, 2 directories
+  Free blocks: 537-8192
+  Free inodes: 22-2048
+Group 1: (Blocks 8193-16384)
+  Backup superblock at 8193, Group descriptors at 8194-8194
+  Reserved GDT blocks at 8195-8450
+  Block bitmap at 8451 (+258), Inode bitmap at 8452 (+259)
+  Inode table at 8453-8708 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 8709-16384
+  Free inodes: 2049-4096
+Group 2: (Blocks 16385-24576)
+  Block bitmap at 16385 (+0), Inode bitmap at 16386 (+1)
+  Inode table at 16387-16642 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 16643-24576
+  Free inodes: 4097-6144
+Group 3: (Blocks 24577-32768)
+  Backup superblock at 24577, Group descriptors at 24578-24578
+  Reserved GDT blocks at 24579-24834
+  Block bitmap at 24835 (+258), Inode bitmap at 24836 (+259)
+  Inode table at 24837-25092 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 25093-32768
+  Free inodes: 6145-8192
+Group 4: (Blocks 32769-40960)
+  Block bitmap at 32769 (+0), Inode bitmap at 32770 (+1)
+  Inode table at 32771-33026 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 33027-40960
+  Free inodes: 8193-10240
+Group 5: (Blocks 40961-49152)
+  Backup superblock at 40961, Group descriptors at 40962-40962
+  Reserved GDT blocks at 40963-41218
+  Block bitmap at 41219 (+258), Inode bitmap at 41220 (+259)
+  Inode table at 41221-41476 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 41477-49152
+  Free inodes: 10241-12288
+Group 6: (Blocks 49153-57344)
+  Block bitmap at 49153 (+0), Inode bitmap at 49154 (+1)
+  Inode table at 49155-49410 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 49411-57344
+  Free inodes: 12289-14336
+Group 7: (Blocks 57345-65536)
+  Backup superblock at 57345, Group descriptors at 57346-57346
+  Reserved GDT blocks at 57347-57602
+  Block bitmap at 57603 (+258), Inode bitmap at 57604 (+259)
+  Inode table at 57605-57860 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 57861-65536
+  Free inodes: 14337-16384
+Group 8: (Blocks 65537-73728)
+  Block bitmap at 65537 (+0), Inode bitmap at 65538 (+1)
+  Inode table at 65539-65794 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 65795-73728
+  Free inodes: 16385-18432
+Group 9: (Blocks 73729-81920)
+  Backup superblock at 73729, Group descriptors at 73730-73730
+  Reserved GDT blocks at 73731-73986
+  Block bitmap at 73987 (+258), Inode bitmap at 73988 (+259)
+  Inode table at 73989-74244 (+260)
+  7676 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 74245-81920
+  Free inodes: 18433-20480
+Group 10: (Blocks 81921-90112)
+  Block bitmap at 81921 (+0), Inode bitmap at 81922 (+1)
+  Inode table at 81923-82178 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 82179-90112
+  Free inodes: 20481-22528
+Group 11: (Blocks 90113-98304)
+  Block bitmap at 90113 (+0), Inode bitmap at 90114 (+1)
+  Inode table at 90115-90370 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 90371-98304
+  Free inodes: 22529-24576
+Group 12: (Blocks 98305-106496)
+  Block bitmap at 98305 (+0), Inode bitmap at 98306 (+1)
+  Inode table at 98307-98562 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 98563-106496
+  Free inodes: 24577-26624
+Group 13: (Blocks 106497-114688)
+  Block bitmap at 106497 (+0), Inode bitmap at 106498 (+1)
+  Inode table at 106499-106754 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 106755-114688
+  Free inodes: 26625-28672
+Group 14: (Blocks 114689-122880)
+  Block bitmap at 114689 (+0), Inode bitmap at 114690 (+1)
+  Inode table at 114691-114946 (+2)
+  7934 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 114947-122880
+  Free inodes: 28673-30720
+Group 15: (Blocks 122881-131071)
+  Block bitmap at 122881 (+0), Inode bitmap at 122882 (+1)
+  Inode table at 122883-123138 (+2)
+  7933 free blocks, 2048 free inodes, 0 directories
+  Free blocks: 123139-131071
+  Free inodes: 30721-32768
tests/m_project/script new file +7 -0
new file mode 100644
index 000000000000..a420ae523c6b
@@ -0,0 +1,7 @@
+DESCRIPTION="enable project feature on mkfs"
+FS_SIZE=131072
+MKE2FS_OPTS="-O project"
+DUMPE2FS_IGNORE_80COL=1
+export DUMPE2FS_IGNORE_80COL
+. $cmd_dir/run_mke2fs
+unset DUMPE2FS_IGNORE_80COL
tests/t_project_1on/expect new file +66 -0

66 lines not on this page · raw message

tests/t_project_1on/name new file +1 -0
new file mode 100644
index 000000000000..e9113aa7d10f
@@ -0,0 +1 @@
+enable project quota using tune2fs
tests/t_project_1on/script new file +68 -0

68 lines not on this page · raw message

tests/t_project_2off/expect new file +78 -0

78 lines not on this page · raw message

tests/t_project_2off/name new file +1 -0
new file mode 100644
index 000000000000..b7e9993d6ddc
@@ -0,0 +1 @@
+disable project quota using tune2fs
tests/t_project_2off/script new file +54 -0

54 lines not on this page · raw message