From: adas@sourceware.org <adas@sourceware.org>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] cluster/gfs2 libgfs2/ondisk.c quota/check.c qu ...
Date: 24 Aug 2007 06:08:22 -0000 [thread overview]
Message-ID: <20070824060822.14488.qmail@sourceware.org> (raw)
CVSROOT: /cvs/cluster
Module name: cluster
Branch: RHEL5
Changes by: adas at sourceware.org 2007-08-24 06:08:21
Modified files:
gfs2/libgfs2 : ondisk.c
gfs2/quota : check.c gfs2_quota.h main.c
Log message:
fix for bz253016: userland fixes for gfs2 quota linked list
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/ondisk.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.5.2.1&r2=1.5.2.2
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/quota/check.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.2.2.3&r2=1.2.2.4
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/quota/gfs2_quota.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.1.2.3&r2=1.1.2.4
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/quota/main.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.2.2.4&r2=1.2.2.5
--- cluster/gfs2/libgfs2/ondisk.c 2007/06/18 21:50:00 1.5.2.1
+++ cluster/gfs2/libgfs2/ondisk.c 2007/08/24 06:08:21 1.5.2.2
@@ -252,6 +252,8 @@
CPIN_64(qu, str, qu_limit);
CPIN_64(qu, str, qu_warn);
CPIN_64(qu, str, qu_value);
+ CPIN_32(qu, str, qu_ll_next);
+ CPIN_08(qu, str, qu_reserved, 60);
}
void gfs2_quota_out(struct gfs2_quota *qu, char *buf)
@@ -261,7 +263,8 @@
CPOUT_64(qu, str, qu_limit);
CPOUT_64(qu, str, qu_warn);
CPOUT_64(qu, str, qu_value);
- memset(qu->qu_reserved, 0, sizeof(qu->qu_reserved));
+ CPOUT_32(qu, str, qu_ll_next);
+ CPOUT_08(qu, str, qu_reserved, 60);
}
void gfs2_quota_print(struct gfs2_quota *qu)
--- cluster/gfs2/quota/check.c 2007/05/31 22:39:15 1.2.2.3
+++ cluster/gfs2/quota/check.c 2007/08/24 06:08:21 1.2.2.4
@@ -187,8 +187,8 @@
char buf[sizeof(struct gfs2_quota)];
struct gfs2_quota q;
uint64_t offset = 0;
- uint32_t id;
- int error;
+ uint32_t id, prev, maxid;
+ int error, pass, id_type;
char quota_file[BUF_SIZE];
strcpy(sdp->path_name, comline->filesystem);
@@ -209,6 +209,33 @@
strerror(errno));
}
+ if (!is_valid_quota_list(fd)) {
+ print_quota_list_warning();
+ goto do_old_school;
+ }
+ get_last_quota_id(fd, &maxid);
+
+ for (pass=0; pass<2; pass++) {
+ id = 0;
+ id_type = pass ? GQ_ID_GROUP : GQ_ID_USER;
+
+ do {
+ read_quota_internal(fd, id, id_type, &q);
+ prev = id;
+ q.qu_value <<= sdp->sd_sb.sb_bsize_shift - 9;
+
+ if (q.qu_value) {
+ if (pass)
+ add_value(gid, id, q.qu_value);
+ else
+ add_value(uid, id, q.qu_value);
+ }
+ id = q.qu_ll_next;
+ } while(id && id > prev && id <= maxid);
+ }
+ goto out;
+
+do_old_school:
do {
memset(buf, 0, sizeof(struct gfs2_quota));
@@ -237,6 +264,7 @@
offset += sizeof(struct gfs2_quota);
} while (error == sizeof(struct gfs2_quota));
+out:
close(fd);
close(sdp->metafs_fd);
cleanup_metafs(sdp);
--- cluster/gfs2/quota/gfs2_quota.h 2007/05/31 22:39:15 1.1.2.3
+++ cluster/gfs2/quota/gfs2_quota.h 2007/08/24 06:08:21 1.1.2.4
@@ -58,6 +58,7 @@
#define GQ_OP_WARN (16)
#define GQ_OP_CHECK (17)
#define GQ_OP_INIT (18)
+#define GQ_OP_RESET (19)
#define GQ_ID_USER (23)
#define GQ_ID_GROUP (24)
@@ -97,6 +98,13 @@
void mount_gfs2_meta();
void cleanup();
void read_superblock(struct gfs2_sb *sb, struct gfs2_sbd *sdp);
+void get_last_quota_id(int fd, uint32_t *max_id);
+int is_valid_quota_list(int fd);
+inline void read_quota_internal(int fd, unsigned int id, int id_type,
+ struct gfs2_quota *q);
+inline void write_quota_internal(int fd, unsigned int id, int id_type,
+ struct gfs2_quota *q);
+void print_quota_list_warning();
/* check.c */
--- cluster/gfs2/quota/main.c 2007/05/31 22:39:15 1.2.2.4
+++ cluster/gfs2/quota/main.c 2007/08/24 06:08:21 1.2.2.5
@@ -77,6 +77,7 @@
printf(" warn set a quota warning value for an ID\n");
printf(" check check the quota file\n");
printf(" init initialize the quota file\n");
+ printf(" reset reset the quota file\n");
printf("\n");
printf("Options:\n");
printf(" -b sizes are in FS blocks\n");
@@ -214,6 +215,10 @@
if (comline->operation)
die("can't specify two operations\n");
comline->operation = GQ_OP_INIT;
+ } else if (strcmp(argv[optind], "reset") == 0) {
+ if (comline->operation)
+ die("can't specify two operations\n");
+ comline->operation = GQ_OP_RESET;
} else
die("unknown option %s\n", argv[optind]);
@@ -297,6 +302,239 @@
close(fd);
}
+inline void
+read_quota_internal(int fd, uint32_t id, int id_type, struct gfs2_quota *q)
+{
+ /* seek to the appropriate offset in the quota file and read the
+ quota info */
+ uint64_t offset;
+ char buf[256];
+ int error;
+ if (id_type == GQ_ID_USER)
+ offset = (2 * (uint64_t)id) * sizeof(struct gfs2_quota);
+ else
+ offset = (2 * (uint64_t)id + 1) * sizeof(struct gfs2_quota);
+ lseek(fd, offset, SEEK_SET);
+ error = read(fd, buf, sizeof(struct gfs2_quota));
+ if (error < 0)
+ die("failed to read from quota file: %s\n", strerror(errno));
+ if (error != sizeof(struct gfs2_quota))
+ die("Couldn't read %d bytes from quota file@offset %llu\n",
+ sizeof(struct gfs2_quota), offset);
+ gfs2_quota_in(q, buf);
+}
+
+inline void
+write_quota_internal(int fd, uint32_t id, int id_type, struct gfs2_quota *q)
+{
+ /* seek to the appropriate offset in the quota file and read the
+ quota info */
+ uint64_t offset;
+ char buf[256];
+ int error;
+ if (id_type == GQ_ID_USER)
+ offset = (2 * (uint64_t)id) * sizeof(struct gfs2_quota);
+ else
+ offset = (2 * (uint64_t)id + 1) * sizeof(struct gfs2_quota);
+ lseek(fd, offset, SEEK_SET);
+ gfs2_quota_out(q, buf);
+ error = write(fd, buf, sizeof(struct gfs2_quota));
+ if (error != sizeof(struct gfs2_quota))
+ die("failed to write to quota file: %s\n", strerror(errno));
+}
+
+/**
+ * get_last_quota_id - Get the last quota in the quota file
+ * @fd: an open file descriptor of the quota file
+ * @id_type: GQ_ID_USER or GQ_ID_GROUP
+ * @max_id: return the maximum id obtained
+ */
+void
+get_last_quota_id(int fd, uint32_t *max_id)
+{
+ /* stat(2) the quota file to find how big it is. This will give us a
+ * a rough idea of what the last valid quota uid/gid is. It is possible
+ * that the last quota in the file belongs to a group with gid:x and
+ * the corresponding user quota with uid:x doesn't exist. In such cases
+ * we still return x as max_id. This max_id is ONLY A HINT. If used
+ * as a terminating condition of a loop, another condition should also
+ * be specified.
+ */
+ struct stat st;
+ uint32_t qsize = sizeof(struct gfs2_quota);
+ uint64_t size;
+ if (fstat(fd, &st))
+ die("failed to stat the quota file: %s\n", strerror(errno));
+ size = st.st_size;
+ if (!size)
+ die("error: quota file is truncated to zero!\n");
+ if (size % qsize) {
+ printf("warning: quota file size not a multiple of "
+ "struct gfs2_quota\n");
+ size = qsize * (size / qsize);
+ }
+ *max_id = (size - 1) / (2 * qsize);
+}
+
+/**
+ * is_valid_quota_list - Check if we have a valid quota list
+ * @fd: an open file descriptor of the quota file
+ * Returns 0 or 1.
+ */
+int
+is_valid_quota_list(int fd)
+{
+ /* This is a slow test to determine if the quotas are in a
+ * linked list. We should come up with something better
+ * Quota linked list format is identified by the following.
+ * step1: Get the maximum groupid and userid having valid
+ * quotas in the quota file.
+ * step2: Obtain the size of the quota file. The size of the
+ * quota file (position of the last valid quota)
+ * determines the last user/group id.
+ * step3: If we can obtain the last valid quota through the
+ * lists, then our lists are good. Else, the lists are
+ * either corrupt or an older quota file format is in use
+ */
+ int id_type = GQ_ID_GROUP;
+ uint32_t id = 0, prev, ulast = 0, glast = 0, max;
+ struct gfs2_quota q;
+
+ get_last_quota_id(fd, &max);
+again:
+ do {
+ read_quota_internal(fd, id, id_type, &q);
+ prev = id;
+ id = q.qu_ll_next;
+ if (id > max)
+ return 0;
+ } while (id && id > prev);
+
+ if (id && id <= prev)
+ return 0;
+
+ if (id_type == GQ_ID_GROUP)
+ glast = prev;
+ else
+ ulast = prev;
+
+ if (id_type == GQ_ID_GROUP) {
+ id_type = GQ_ID_USER;
+ id = 0;
+ goto again;
+ }
+
+ if (glast != max && ulast != max)
+ return 0;
+
+ return 1;
+}
+
+void
+print_quota_list_warning()
+{
+ printf("\nWarning: This filesystem doesn't seem to have the new quota "
+ "list format or the quota list is corrupt. list, check and init "
+ "operation performance will suffer due to this. It is recommended "
+ "that you run the 'gfs2_quota reset' operation to reset the quota "
+ "file. All current quota information will be lost and you will "
+ "have to reassign all quota limits and warnings\n\n");
+}
+
+/**
+ * adjust_quota_list - Adjust the quota linked list
+ * @fd: The quota file descriptor
+ * @comline: the struct containing the parsed command line arguments
+ */
+static void
+adjust_quota_list(int fd, commandline_t *comline)
+{
+ uint32_t prev = 0, next = 0, id = comline->id;
+ struct gfs2_quota tmpq, q;
+ int id_type = comline->id_type;
+
+ if (id == 0) /* root quota, don't do anything */
+ goto out;
+ /* We just wrote the quota for id in do_set(). Get it */
+ next = 0;
+ do {
+ read_quota_internal(fd, next, id_type, &q);
+ prev = next;
+ next = q.qu_ll_next;
+ if (prev == id) /* no duplicates, bail */
+ goto out;
+ if (prev < id && id < next) /* gotcha! */
+ break;
+ } while(next && next > prev);
+ read_quota_internal(fd, id, id_type, &tmpq);
+ tmpq.qu_ll_next = next;
+ q.qu_ll_next = id;
+ write_quota_internal(fd, id, id_type, &tmpq);
+ write_quota_internal(fd, prev, id_type, &q);
+
+out:
+ return;
+}
+
+/**
+ * do_reset - Reset all the quota data for a filesystem
+ * @comline: the struct containing the parsed command line arguments
+ */
+
+static void
+do_reset(struct gfs2_sbd *sdp, commandline_t *comline)
+{
+ int fd;
+ char quota_file[BUF_SIZE], c;
+ struct gfs2_quota q;
+
+ if (!*comline->filesystem)
+ die("need a filesystem to work on\n");
+
+ printf("This operation will permanently erase all quota information. "
+ "You will have to re-assign all quota limit/warn values. "
+ "Proceed [y/N]? ");
+ c = getchar();
+ if (c != 'y' && c != 'Y')
+ return;
+
+ strcpy(sdp->path_name, comline->filesystem);
+ check_for_gfs2(sdp);
+ read_superblock(&sdp->sd_sb, sdp);
+ if (!find_gfs2_meta(sdp))
+ mount_gfs2_meta(sdp);
+ lock_for_admin(sdp);
+
+ strcpy(quota_file, sdp->metafs_path);
+ strcat(quota_file, "/quota");
+
+ fd = open(quota_file, O_RDWR);
+ if (fd < 0) {
+ close(sdp->metafs_fd);
+ cleanup_metafs(sdp);
+ die("can't open file %s: %s\n", quota_file,
+ strerror(errno));
+ }
+
+ read_quota_internal(fd, 0, GQ_ID_USER, &q);
+ q.qu_ll_next = 0;
+ write_quota_internal(fd, 0, GQ_ID_USER, &q);
+
+ read_quota_internal(fd, 0, GQ_ID_GROUP, &q);
+ q.qu_ll_next = 0;
+ write_quota_internal(fd, 0, GQ_ID_GROUP, &q);
+
+ /* truncate the quota file such that only the first
+ * two quotas(uid=0 and gid=0) remain.
+ */
+ if (ftruncate(fd, (sizeof(struct gfs2_quota)) * 2))
+ die("couldn't truncate quota file %s\n", strerror(errno));
+
+ close(fd);
+ close(sdp->metafs_fd);
+ cleanup_metafs(sdp);
+}
+
/**
* do_list - List all the quota data for a filesystem
* @comline: the struct containing the parsed command line arguments
@@ -310,10 +548,11 @@
struct gfs2_quota q;
char buf[sizeof(struct gfs2_quota)];
uint64_t offset;
- uint32_t id;
+ uint32_t id, prev, maxid;
int pass = 0;
int error = 0;
char quota_file[BUF_SIZE];
+ int id_type = comline->id_type;
if (!*comline->filesystem)
die("need a filesystem to work on\n");
@@ -335,6 +574,30 @@
die("can't open file %s: %s\n", quota_file,
strerror(errno));
}
+
+ if (!is_valid_quota_list(fd)) {
+ print_quota_list_warning();
+ goto do_old_school;
+ }
+ get_last_quota_id(fd, &maxid);
+
+ for (pass=0; pass<2; pass++) {
+ id = 0;
+ id_type = pass ? GQ_ID_GROUP : GQ_ID_USER;
+
+ do {
+ read_quota_internal(fd, id, id_type, &q);
+ prev = id;
+ if (q.qu_limit || q.qu_warn || q.qu_value)
+ print_quota(comline,
+ id_type == GQ_ID_USER ? TRUE : FALSE,
+ id, &q, &sdp->sd_sb);
+ id = q.qu_ll_next;
+ } while(id && id > prev && id <= maxid);
+ }
+ goto out;
+
+do_old_school:
for (pass=0; pass<2; pass++) {
if (!pass)
offset = 0;
@@ -359,7 +622,7 @@
offset += 2 * sizeof(struct gfs2_quota);
} while (error == sizeof(struct gfs2_quota));
}
-
+out:
close(fd);
close(sdp->metafs_fd);
cleanup_metafs(sdp);
@@ -380,6 +643,7 @@
struct gfs2_quota q;
uint64_t offset;
int error;
+ uint32_t maxid;
char quota_file[BUF_SIZE];
strcpy(sdp->path_name, filesystem);
@@ -407,6 +671,10 @@
memset(&q, 0, sizeof(struct gfs2_quota));
+ get_last_quota_id(fd, &maxid);
+ if (comline->id > maxid)
+ goto print_empty_quota;
+
lseek(fd, offset, SEEK_SET);
error = read(fd, buf, sizeof(struct gfs2_quota));
if (error < 0) {
@@ -420,6 +688,7 @@
gfs2_quota_in(&q, buf);
+print_empty_quota:
print_quota(comline,
(comline->id_type == GQ_ID_USER), comline->id,
&q, &sdp->sd_sb);
@@ -543,7 +812,7 @@
int fd, fd1;
uint64_t offset;
uint64_t new_value;
- int error;
+ int error, adj_flag = 0;;
char quota_file[BUF_SIZE];
char sys_q_refresh[BUF_SIZE];
char id_str[16];
@@ -564,7 +833,7 @@
strcpy(quota_file, sdp->metafs_path);
strcat(quota_file, "/quota");
- fd = open(quota_file, O_WRONLY);
+ fd = open(quota_file, O_RDWR);
if (fd < 0) {
close(sdp->metafs_fd);
cleanup_metafs(sdp);
@@ -572,6 +841,11 @@
strerror(errno));
}
+ if (is_valid_quota_list(fd))
+ adj_flag = 1;
+ else
+ print_quota_list_warning();
+
switch (comline->id_type) {
case GQ_ID_USER:
offset = (2 * (uint64_t)comline->id) * sizeof(struct gfs2_quota);
@@ -706,6 +980,8 @@
goto out;
}
close(fd1);
+ if (adj_flag)
+ adjust_quota_list(fd, comline);
out:
close(fd);
close(sdp->metafs_fd);
@@ -765,6 +1041,9 @@
do_quota_init(sdp, &comline);
break;
+ case GQ_OP_RESET:
+ do_reset(sdp, &comline);
+ break;
default:
if (!comline.id_type) {
comline.id_type = GQ_ID_USER;
next reply other threads:[~2007-08-24 6:08 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-08-24 6:08 adas [this message]
-- strict thread matches above, loose matches on Subject: below --
2007-08-24 6:08 [Cluster-devel] cluster/gfs2 libgfs2/ondisk.c quota/check.c qu adas
2007-08-24 6:06 adas
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=20070824060822.14488.qmail@sourceware.org \
--to=adas@sourceware.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.