linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Aditya Kali <adityakali@google.com>
To: linux-ext4@vger.kernel.org
Cc: Aditya Kali <adityakali@google.com>
Subject: [PATCH 4/5] tune2fs: Add support for turning on quota feature
Date: Wed, 20 Jul 2011 11:40:05 -0700	[thread overview]
Message-ID: <1311187206-30553-5-git-send-email-adityakali@google.com> (raw)
In-Reply-To: <1311187206-30553-1-git-send-email-adityakali@google.com>

This patch adds support for setting the quota feature in superblock
and allows selectively creating quota inodes (user or group or both)
in the superblock. Currently, modifying the quota feature is only
supported when the filesystem is unmounted.
Also, when setting the quota feature, tune2fs will use aquota.user or
aquota.group file inode number in superblock if these files exist.
Otherwise it will initialize empty quota inodes #3 and #4 and use them.

Here is how it works:
 # Set quota feature and initialize both (user and group) quota inodes
 $ tune2fs -O quota /dev/ram1

 # Enable only one type of quota
 $ tune2fs -Q usrquota /dev/ram1

 # Enable grpquota, disable usrquota
 $ tune2fs -Q ^usrquota,grpquota /dev/ram1

 # Clear quota feature and remove quota inodes
 $ tune2fs -O ^quota /dev/ram1

Signed-off-by: Aditya Kali <adityakali@google.com>
---
 misc/Makefile.in  |   14 +++--
 misc/tune2fs.8.in |   15 +++++
 misc/tune2fs.c    |  148 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 167 insertions(+), 10 deletions(-)

diff --git a/misc/Makefile.in b/misc/Makefile.in
index 2f7908c..a23adcd 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -143,24 +143,26 @@ e2initrd_helper: e2initrd_helper.o $(DEPLIBS) $(DEPLIBBLKID) $(LIBEXT2FS)
 		$(LIBBLKID) $(LIBEXT2FS) $(LIBINTL)
 
 tune2fs: $(TUNE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBBLKID) \
-		$(DEPLIBUUID) $(LIBEXT2FS) 
+		$(DEPLIBUUID) $(DEPLIBQUOTA) $(LIBEXT2FS)
 	$(E) "	LD $@"
 	$(Q) $(CC) $(ALL_LDFLAGS) -o tune2fs $(TUNE2FS_OBJS) $(LIBS) \
-		$(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBS_E2P) $(LIBINTL)
+		$(LIBBLKID) $(LIBUUID) $(LIBQUOTA) $(LIBEXT2FS) $(LIBS_E2P) \
+		$(LIBINTL)
 
 tune2fs.static: $(TUNE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBE2P) $(DEPSTATIC_LIBBLKID)
 	$(E) "	LD $@"
 	$(Q) $(CC) $(LDFLAGS_STATIC) -o tune2fs.static $(TUNE2FS_OBJS) \
 		$(STATIC_LIBS) $(STATIC_LIBBLKID) $(STATIC_LIBUUID) \
-		$(STATIC_LIBE2P) $(LIBINTL)
+		$(STATIC_LIBQUOTA) $(STATIC_LIBE2P) $(LIBINTL)
 
 tune2fs.profiled: $(PROFILED_TUNE2FS_OBJS) $(PROFILED_DEPLIBS) \
-		$(PROFILED_E2P) $(DEPPROFILED_LIBBLKID) $(DEPPROFILED_LIBUUID)
+		$(PROFILED_E2P) $(DEPPROFILED_LIBBLKID) $(DEPPROFILED_LIBUUID) \
+		$(DEPPROFILED_LIBQUOTA)
 	$(E) "	LD $@"
 	$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o tune2fs.profiled \
 		$(PROFILED_TUNE2FS_OBJS) $(PROFILED_LIBBLKID) \
-		$(PROFILED_LIBUUID) $(PROFILED_LIBE2P) $(LIBINTL) \
-		$(PROFILED_LIBS) 
+		$(PROFILED_LIBUUID) $(PROFILED_LIBQUOTA) $(PROFILED_LIBE2P) \
+		$(LIBINTL) $(PROFILED_LIBS)
 
 blkid: $(BLKID_OBJS) $(DEPLIBBLKID) $(LIBEXT2FS)
 	$(E) "	LD $@"
diff --git a/misc/tune2fs.8.in b/misc/tune2fs.8.in
index 233f85a..89bc1d9 100644
--- a/misc/tune2fs.8.in
+++ b/misc/tune2fs.8.in
@@ -77,6 +77,11 @@ tune2fs \- adjust tunable filesystem parameters on ext2/ext3/ext4 filesystems
 .RI [^] feature [,...]
 ]
 [
+.B \-Q
+.I quota-options
+]
+[
+[
 .B \-T
 .I time-last-checked
 ]
@@ -561,6 +566,16 @@ features are only supported by the ext4 filesystem.
 .BI \-r " reserved-blocks-count"
 Set the number of reserved filesystem blocks.
 .TP
+.BI \-Q " quota-options"
+Sets 'quota' feature on the superblock and works on the quota files for the
+given quota type. Quota options could be one or more of the following:
+.RS 1.2i
+.TP
+.BR [^]usrquota
+Sets/clears user quota inode in the superblock.
+.BR [^]usrquota
+Sets/clears group quota inode in the superblock.
+.TP
 .BI \-T " time-last-checked"
 Set the time the filesystem was last checked using
 .BR  e2fsck .
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 5bf5187..3c81898 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -55,16 +55,22 @@ extern int optind;
 #include "jfs_user.h"
 #include "util.h"
 #include "blkid/blkid.h"
+#include "quota/mkquota.h"
 
 #include "../version.h"
 #include "nls-enable.h"
 
+#define QOPT_ENABLE	(1)
+#define QOPT_DISABLE	(-1)
+
+extern int ask_yn(const char *string, int def);
+
 const char *program_name = "tune2fs";
 char *device_name;
 char *new_label, *new_last_mounted, *new_UUID;
 char *io_options;
 static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
-static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
+static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
 static int I_flag;
 static time_t last_check_time;
 static int print_label;
@@ -82,6 +88,7 @@ static int stride_set, stripe_width_set;
 static char *extended_cmd;
 static unsigned long new_inode_size;
 static char *ext_mount_opts;
+static int usrquota, grpquota;
 
 int journal_size, journal_flags;
 char *journal_device;
@@ -131,7 +138,8 @@ static __u32 ok_features[3] = {
 		EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
 		EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
 		EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
-		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
+		EXT4_FEATURE_RO_COMPAT_QUOTA
 };
 
 static __u32 clear_ok_features[3] = {
@@ -147,7 +155,8 @@ static __u32 clear_ok_features[3] = {
 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
 		EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
 		EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
-		EXT4_FEATURE_RO_COMPAT_GDT_CSUM
+		EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
+		EXT4_FEATURE_RO_COMPAT_QUOTA
 };
 
 /*
@@ -477,6 +486,36 @@ static void update_feature_set(ext2_filsys fs, char *features)
 		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
 	}
 
+	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
+				EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+		/*
+		 * Set the Q_flag here and handle the quota options in the code
+		 * below.
+		 */
+		if (!Q_flag) {
+			Q_flag = 1;
+			/* Enable both user quota and group quota by default */
+			usrquota = QOPT_ENABLE;
+			grpquota = QOPT_ENABLE;
+		}
+		sb->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA;
+	}
+
+	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+				EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+		/*
+		 * Set the Q_flag here and handle the quota options in the code
+		 * below.
+		 */
+		if (Q_flag)
+			fputs(_("\nWarning: '^quota' option overrides '-Q'"
+				"arguments.\n"), stderr);
+		Q_flag = 1;
+		/* Disable both user quota and group quota by default */
+		usrquota = QOPT_DISABLE;
+		grpquota = QOPT_DISABLE;
+	}
+
 	if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
 	    (sb->s_feature_compat || sb->s_feature_ro_compat ||
 	     sb->s_feature_incompat))
@@ -576,6 +615,93 @@ err:
 	exit(1);
 }
 
+void handle_quota_options(ext2_filsys fs)
+{
+	quota_ctx_t qctx;
+	errcode_t retval;
+	ext2_ino_t qf_ino;
+
+	if (!usrquota && !grpquota)
+		/* Nothing to do. */
+		return;
+
+	init_quota_context(&qctx, fs, -1);
+
+	if (usrquota == QOPT_ENABLE && !fs->super->s_usr_quota_inum) {
+		if ((qf_ino = quota_file_exists(fs, USRQUOTA, QFMT_VFS_V1)) > 0)
+			set_sb_quota_inum(fs, qf_ino, USRQUOTA);
+		else
+			write_quota_inode(qctx, USRQUOTA);
+	} else if (usrquota == QOPT_DISABLE) {
+		remove_quota_inode(fs, USRQUOTA);
+	}
+
+	if (grpquota == QOPT_ENABLE && !fs->super->s_grp_quota_inum) {
+		if ((qf_ino = quota_file_exists(fs, GRPQUOTA, QFMT_VFS_V1)) > 0)
+			set_sb_quota_inum(fs, qf_ino, GRPQUOTA);
+		else
+			write_quota_inode(qctx, GRPQUOTA);
+	} else if (grpquota == QOPT_DISABLE) {
+		remove_quota_inode(fs, GRPQUOTA);
+	}
+
+	release_quota_context(&qctx);
+
+	if ((usrquota == QOPT_ENABLE) || (grpquota == QOPT_ENABLE)) {
+		fs->super->s_feature_ro_compat |= EXT4_FEATURE_RO_COMPAT_QUOTA;
+		ext2fs_mark_super_dirty(fs);
+	} else if ((usrquota == QOPT_DISABLE) && (grpquota == QOPT_DISABLE)) {
+		fs->super->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA;
+		ext2fs_mark_super_dirty(fs);
+	}
+
+	return;
+}
+
+void parse_quota_opts(const char *opts)
+{
+	char	*buf, *token, *next, *p, *arg;
+	int	len;
+
+	len = strlen(opts);
+	buf = malloc(len+1);
+	if (!buf) {
+		fputs(_("Couldn't allocate memory to parse quota "
+			"options!\n"), stderr);
+		exit(1);
+	}
+	strcpy(buf, opts);
+	for (token = buf; token && *token; token = next) {
+		p = strchr(token, ',');
+		next = 0;
+		if (p) {
+			*p = 0;
+			next = p+1;
+		}
+
+		if (strcmp(token, "usrquota") == 0) {
+			usrquota = QOPT_ENABLE;
+		} else if (strcmp(token, "^usrquota") == 0) {
+			usrquota = QOPT_DISABLE;
+		} else if (strcmp(token, "grpquota") == 0) {
+			grpquota = QOPT_ENABLE;
+		} else if (strcmp(token, "^grpquota") == 0) {
+			grpquota = QOPT_DISABLE;
+		} else {
+			fputs(_("\nBad quota options specified.\n\n"
+				"Following valid quota options are available "
+				"(pass by separating with comma):\n"
+				"\t[^]usrquota\n"
+				"\t[^]grpquota\n"
+				"\n\n"), stderr);
+			free(buf);
+			exit(1);
+		}
+	}
+	free(buf);
+}
+
+
 
 static void parse_e2label_options(int argc, char ** argv)
 {
@@ -641,7 +767,7 @@ static void parse_tune2fs_options(int argc, char **argv)
 	open_flag = 0;
 
 	printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
-	while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:")) != EOF)
+	while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:Q:T:U:")) != EOF)
 		switch (c) {
 		case 'c':
 			max_mount_count = strtol(optarg, &tmp, 0);
@@ -796,6 +922,11 @@ static void parse_tune2fs_options(int argc, char **argv)
 			features_cmd = optarg;
 			open_flag = EXT2_FLAG_RW;
 			break;
+		case 'Q':
+			Q_flag = 1;
+			parse_quota_opts(optarg);
+			open_flag = EXT2_FLAG_RW;
+			break;
 		case 'r':
 			reserved_blocks = strtoul(optarg, &tmp, 0);
 			if (*tmp) {
@@ -1790,6 +1921,15 @@ retry_open:
 	if (journal_size || journal_device)
 		add_journal(fs);
 
+	if (Q_flag) {
+		if (mount_flags & EXT2_MF_MOUNTED) {
+			fputs(_("The quota feature may only be changed when "
+				"the filesystem is unmounted.\n"), stderr);
+			exit(1);
+		}
+		handle_quota_options(fs);
+	}
+
 	if (U_flag) {
 		int set_csum = 0;
 		dgrp_t i;
-- 
1.7.3.1


  parent reply	other threads:[~2011-07-20 18:41 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-20 18:40 [PATCH 0/5] e2fsprogs: support quota as first class feature in ext4 Aditya Kali
2011-07-20 18:40 ` [PATCH 1/5] e2fsprogs: add quota library to e2fsprogs Aditya Kali
2011-09-09 22:53   ` Andreas Dilger
2011-09-10  3:31     ` Aditya Kali
2011-07-20 18:40 ` [PATCH 2/5] e2fsprogs: Make quota as a supported feature Aditya Kali
2011-07-20 18:40 ` [PATCH 3/5] mke2fs: support creation of filesystem with quota feature Aditya Kali
2011-07-20 18:40 ` Aditya Kali [this message]
2011-09-09 22:39   ` [PATCH 4/5] tune2fs: Add support for turning on " Andreas Dilger
2011-09-09 23:41     ` Aditya Kali
2011-07-20 18:40 ` [PATCH 5/5] e2fsck: check quota accounting during fsck Aditya Kali
2011-07-20 22:03   ` Aditya Kali

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1311187206-30553-5-git-send-email-adityakali@google.com \
    --to=adityakali@google.com \
    --cc=linux-ext4@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).