[Cluster-devel] cluster/gfs/gfs_quota gfs_quota.h main.c Makef ...

adas at sourceware.org adas at sourceware.org
Thu Jan 24 18:29:14 UTC 2008


CVSROOT:	/cvs/cluster
Module name:	cluster
Branch: 	RHEL5
Changes by:	adas at sourceware.org	2008-01-24 18:29:13

Modified files:
	gfs/gfs_quota  : gfs_quota.h main.c Makefile 
Added files:
	gfs/gfs_quota  : layout.c 

Log message:
	fix for bug 430133 - We don't run through the entire gfs_quota sparse file to do a list operation anymore. We get the layout of the gfs_quota file on disk and only read quota information off the data blocks that are actually in use. This is the userland (gfs_quota) part of the fix. There is another accompanying gfs-kernel fix (bz 430134)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs/gfs_quota/layout.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=NONE&r2=1.3.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs/gfs_quota/gfs_quota.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.2&r2=1.2.16.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs/gfs_quota/main.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.3&r2=1.3.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs/gfs_quota/Makefile.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.5&r2=1.5.2.1

/cvs/cluster/cluster/gfs/gfs_quota/layout.c,v  -->  standard output
revision 1.3.2.1
--- cluster/gfs/gfs_quota/layout.c
+++ -	2008-01-24 18:29:13.782331000 +0000
@@ -0,0 +1,614 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include <errno.h>
+
+#define __user
+#include <linux/gfs_ioctl.h>
+#include <linux/gfs_ondisk.h>
+
+#include "osi_list.h"
+#include "linux_endian.h"
+
+#include "gfs_quota.h"
+
+#define LAYOUT_DATA_QUANTUM (4194304)
+
+extern void
+print_quota(commandline_t *comline,
+            int user, uint32_t id,
+            struct gfs_quota *q,
+            struct gfs_sb *sb);
+
+struct extent {
+        osi_list_t list;
+
+        uint64_t offset;
+        uint64_t start;
+        unsigned int len;
+};
+typedef struct extent extent_t;
+
+struct buffer {
+        osi_list_t list;
+        uint64_t blkno;
+        char *data;
+
+        int touched;
+};
+typedef struct buffer buffer_t;
+
+struct lblk_range {
+        osi_list_t list;
+        
+        uint64_t start;
+        unsigned int len;
+};
+typedef struct lblk_range lblk_range_t;
+
+struct world {
+        char *buf_data;
+        unsigned int buf_size;
+        int buf_count;
+        osi_list_t blist;
+        osi_list_t elist;
+
+        struct gfs_sb sb;
+        unsigned int diptrs;
+        unsigned int inptrs;
+        unsigned int jbsize;
+        unsigned int hash_bsize;
+        unsigned int hash_ptrs;
+
+        buffer_t *dibh;
+        struct gfs_dinode di;
+};
+typedef struct world world_t;
+
+typedef void (*pointer_call_t) (world_t *w,
+                                unsigned int height, uint64_t bn, void *data);
+
+static lblk_range_t *lblk_range_list;
+static unsigned int j_blk_size;
+
+/**
+ * add_lblk_range - Add a range of logical block numbers to lblk_list
+ * @lblk_list: the list to add to
+ * @start: the starting block number of the range
+ * @len: the length of the range
+ *
+ */
+
+static void 
+add_lblk_range(lblk_range_t *lblk_list, uint64_t start, unsigned int len)
+{
+        lblk_range_t *tmp;
+
+        tmp = malloc(sizeof(lblk_range_t));
+        if (!tmp)
+                die("out of memory\n");
+        
+        tmp->start = start;
+        tmp->len = len;
+        
+        osi_list_add_prev(&tmp->list, &lblk_list->list);
+}
+
+/**
+ * build_list - build a list of buffer_t's to represent the data from the kernel
+ * @w: the world structure
+ *
+ */
+
+static void
+build_list(world_t *w)
+{
+        buffer_t *b;
+        unsigned int x;
+
+        for (x = 0; x < w->buf_count; x += sizeof(uint64_t) + w->sb.sb_bsize) {
+                b = malloc(sizeof(buffer_t));
+                if (!b)
+                        die("out of memory\n");
+
+                memset(b, 0, sizeof(buffer_t));
+
+                b->blkno = *(uint64_t *) (w->buf_data + x);
+                b->data = w->buf_data + x + sizeof(uint64_t);
+
+                osi_list_add_prev(&b->list, &w->blist);
+        }
+
+        if (x != w->buf_count)
+                die("the kernel passed back unaligned data\n");
+}
+
+/**
+ * check_list - check the buffers passed back by the kernel
+ * @w: the world
+ *
+ */
+
+static void
+check_list(world_t *w)
+{
+        osi_list_t *tmp;
+        buffer_t *b;
+        struct gfs_meta_header mh;
+        char *type;
+
+        for (tmp = w->blist.next; tmp != &w->blist; tmp = tmp->next) {
+                b = osi_list_entry(tmp, buffer_t, list);
+
+                gfs_meta_header_in(&mh, b->data);
+
+                if (mh.mh_magic != GFS_MAGIC)
+                        die("bad magic number on block\n");
+
+                switch (mh.mh_type) {
+                case GFS_METATYPE_DI:
+                        type = "GFS_METATYPE_DI";
+
+                        if (w->dibh)
+                                die("more than one dinode in file\n");
+                        else {
+                                w->dibh = b;
+                                gfs_dinode_in(&w->di, b->data);
+
+                                b->touched = TRUE;
+                        }
+                        break;
+                case GFS_METATYPE_IN:
+                        type = "GFS_METATYPE_IN";
+                        break;
+                case GFS_METATYPE_LF:
+                        type = "GFS_METATYPE_LF";
+                        break;
+                case GFS_METATYPE_JD:
+                        type = "GFS_METATYPE_JD";
+                        break;
+                case GFS_METATYPE_EA:
+                        type = "GFS_METATYPE_EA";
+                        break;
+                case GFS_METATYPE_ED:
+                        die("GFS_METATYPE_ED shouldn't be present\n");
+                default:
+                        die("strange meta type\n");
+                }
+        }
+
+        if (!w->dibh)
+                die("no dinode\n");
+}
+
+/**
+ * getbuf - get the buffer_t for a given block number
+ * @w: the world
+ * @blkno: the block number
+ *
+ * Returns: the buffer_t
+ */
+
+static buffer_t *
+getbuf(world_t *w, uint64_t blkno)
+{
+        osi_list_t *tmp;
+        buffer_t *b;
+
+        for (tmp = w->blist.next; tmp != &w->blist; tmp = tmp->next) {
+                b = osi_list_entry(tmp, buffer_t, list);
+                if (b->blkno == blkno) {
+                        osi_list_del(&b->list);
+                        osi_list_add(&b->list, &w->blist);
+
+                        b->touched = TRUE;
+
+                        return b;
+                }
+        }
+
+        die("buffer not found\n");
+}
+
+/**
+ * recursive_scan - call a function for each block pointer in a file
+ * @w: the world
+ * @height: the height of the block being pointed to
+ * @block: the block being pointed to
+ * @pc: the function to call
+ * @data: private data for the @pc function
+ *
+ */
+
+static void
+recursive_scan(world_t *w, unsigned int height, 
+               uint64_t block, pointer_call_t pc, void *data)
+{
+        buffer_t *b = NULL;
+        uint64_t *top, *bottom;
+        uint64_t bn;
+
+        if (!height) {
+                b = w->dibh;
+
+                top = (uint64_t *) (b->data + sizeof(struct gfs_dinode));
+                bottom =
+                    (uint64_t *) (b->data + sizeof(struct gfs_dinode)) +
+                    w->diptrs;
+        } else {
+                b = getbuf(w, block);
+
+                top = (uint64_t *) (b->data + sizeof(struct gfs_indirect));
+                bottom =
+                    (uint64_t *) (b->data + sizeof(struct gfs_indirect)) +
+                    w->inptrs;
+        }
+
+        for (; top < bottom; top++) {
+                bn = gfs64_to_cpu(*top);
+
+                pc(w, height, bn, data);
+
+                if (bn && height < w->di.di_height - 1)
+                        recursive_scan(w, height + 1, bn, pc, data);
+        }
+}
+
+/**
+ * add_extent - add an extend to the list of the file's data extents
+ * @w: the world
+ * @offset: the starting logical block of the extent
+ * @start: the starting disk block of the extent
+ * @len: the number of blocks in the extent
+ *
+ */
+
+static void
+add_extent(world_t *w, uint64_t offset, uint64_t start, unsigned int len)
+{
+        extent_t *e;
+
+        e = malloc(sizeof(extent_t));
+        if (!e)
+                die("out of memory\n");
+
+        memset(e, 0, sizeof(extent_t));
+
+        e->offset = offset;
+        e->start = start;
+        e->len = len;
+
+        osi_list_add_prev(&e->list, &w->elist);
+}
+
+struct do_pf_s {
+        unsigned int height;
+        uint64_t offset;
+        uint64_t start;
+        uint64_t skip;
+        unsigned int len;
+};
+typedef struct do_pf_s do_pf_t;
+
+/**
+ * do_pf: called for every pointer in the file (prints/collects extent info)
+ * @w: the world
+ * @height: the height of the block containing the pointer
+ * @bn: the contents of the pointer
+ * @data: a do_pf_t structure
+ *
+ */
+
+static void
+do_pf(world_t *w, unsigned int height, uint64_t bn, void *data)
+{
+        do_pf_t *pf = (do_pf_t *) data;
+        unsigned int x;
+        uint64_t skip;
+
+        if (pf->height < height + 1)
+                return;
+
+        if (!bn) {
+                if (pf->height == height + 1)
+                        pf->skip++;
+                else {
+                        x = pf->height - height - 1;
+                        skip = w->inptrs;
+                        while (--x)
+                                skip *= w->inptrs;
+                        pf->skip += skip;
+                }
+
+                return;
+        }
+
+        if (pf->height == height + 1) {
+                if (pf->start + pf->len == bn && pf->len == pf->skip) {
+                        pf->len++;
+                        pf->skip++;
+                } else {
+                        if (pf->start) {
+                                if (pf->height == w->di.di_height) {
+                                        add_extent(w, pf->offset, pf->start,
+                                                   pf->len);
+                                        add_lblk_range(lblk_range_list, 
+                                                       pf->offset, pf->len);
+                                }
+                        }
+
+                        pf->offset += pf->skip;
+                        pf->start = bn;
+                        pf->len = 1;
+                        pf->skip = 1;
+                }
+        }
+}
+
+/**
+ * get_dblk_ranges - Run through the file and add valid data block ranges to 
+ *                   lblk_range_list
+ * @w: the world
+ *
+ */
+
+static void
+get_dblk_ranges(world_t *w)
+{
+        do_pf_t pf;
+        unsigned int h;
+
+        for (h = 1; h <= w->di.di_height; h++) {
+
+                memset(&pf, 0, sizeof(do_pf_t));
+                pf.height = h;
+
+                recursive_scan(w, 0, 0, do_pf, &pf);
+
+                if (pf.start) {
+                        if (h == w->di.di_height) {
+                                add_extent(w, pf.offset, pf.start, pf.len);
+                                add_lblk_range(lblk_range_list, pf.offset, 
+                                               pf.len);
+                        }
+                }
+        }
+}
+
+/**
+ * compute_layout - Computes the layout and store the valid data page ranges 
+ *                  in lblk_range_list
+ * @argc:
+ * @argv:
+ *
+ */
+
+void
+compute_layout(char *path)
+{
+        world_t w;
+        int fd;
+        int retry = TRUE;
+        struct gfs_ioctl gi;
+        int error;
+
+        memset(&w, 0, sizeof(world_t));
+        w.buf_size = LAYOUT_DATA_QUANTUM;
+        osi_list_init(&w.blist);
+        osi_list_init(&w.elist);
+
+
+        fd = open(path, O_RDONLY);
+        if (fd < 0)
+                die("can't open %s: %s\n", path, strerror(errno));
+
+        check_for_gfs(fd, path);
+
+        {
+                char *argv[] = { "get_super" };
+
+                gi.gi_argc = 1;
+                gi.gi_argv = argv;
+                gi.gi_data = (char *)&w.sb;
+                gi.gi_size = sizeof(struct gfs_sb);
+
+                error = ioctl(fd, GFS_IOCTL_SUPER, &gi);
+                if (error != gi.gi_size)
+                        die("error doing get_super (%d): %s\n",
+                            error, strerror(errno));
+        }
+
+        w.diptrs = (w.sb.sb_bsize - sizeof(struct gfs_dinode)) /
+                sizeof(uint64_t);
+        w.inptrs = (w.sb.sb_bsize - sizeof(struct gfs_indirect)) /
+                sizeof(uint64_t);
+        w.jbsize = w.sb.sb_bsize - sizeof(struct gfs_meta_header);
+        j_blk_size = w.jbsize;
+        w.hash_bsize = w.sb.sb_bsize / 2;
+        w.hash_ptrs = w.hash_bsize / sizeof(uint64_t);
+
+        for (;;) {
+                char *argv[] = { "get_file_meta_quota" };
+
+                w.buf_data = malloc(w.buf_size);
+                if (!w.buf_data)
+                        die("out of memory\n");
+
+                gi.gi_argc = 1;
+                gi.gi_argv = argv;
+                gi.gi_data = w.buf_data;
+                gi.gi_size = w.buf_size;
+
+                w.buf_count = ioctl(fd, GFS_IOCTL_SUPER, &gi);
+                if (w.buf_count >= 0)
+                        break;
+
+                if (errno == ENOMEM) {
+                        if (retry) {
+                                free(w.buf_data);
+                                w.buf_size += LAYOUT_DATA_QUANTUM;
+                                continue;
+                        } else
+                                die("%u bytes isn't enough memory\n",
+                                    w.buf_size);
+                }
+                die("error doing get_file_meta: %s\n",
+                    strerror(errno));
+        }
+
+        build_list(&w);
+        check_list(&w);
+
+        get_dblk_ranges(&w);
+
+        close(fd);
+}
+
+/**
+ * print_quota_range - print the quota information in the given sequence of 
+ *                     blocks
+ * @argc:
+ * @argv:
+ *
+ */
+void 
+print_quota_range(commandline_t *comline, int type, uint64_t start, 
+                  unsigned int len)
+{
+        uint64_t blk_offt, blk_end_offt, offset;
+        uint64_t quo;
+        unsigned int rem;
+        int fd;
+        struct gfs_sb sb;
+        struct gfs_ioctl gi;
+        char buf[sizeof(struct gfs_quota)];
+        struct gfs_quota q;
+        uint64_t hidden_blocks = 0;
+        uint32_t id;
+        int error;
+
+        blk_offt = start * (uint64_t)j_blk_size;
+        blk_end_offt = blk_offt + (uint64_t)(len * j_blk_size);
+
+        quo = blk_offt / (uint64_t)(2 * sizeof(struct gfs_quota));
+        rem = blk_offt % (uint64_t)(2 * sizeof(struct gfs_quota));
+        
+        offset = type == GQ_ID_USER ? blk_offt : 
+                blk_offt + sizeof(struct gfs_quota);
+        
+        if (rem && type == GQ_ID_USER)
+                offset = (quo + 1) * (uint64_t)(2 * sizeof(struct gfs_quota));
+        
+        if (rem && type == GQ_ID_GROUP) {
+                if (rem <= sizeof(struct gfs_quota))
+                        offset = quo * (uint64_t)(2 * sizeof(struct gfs_quota))
+                                + sizeof(struct gfs_quota);
+                else
+                        offset = (quo + 1) * 
+                                (uint64_t)(2 * sizeof(struct gfs_quota)) + 
+                                sizeof(struct gfs_quota);
+        }
+
+        fd = open(comline->filesystem, O_RDONLY);
+        if (fd < 0)
+                die("can't open file %s: %s\n", comline->filesystem, 
+                    strerror(errno));
+
+        check_for_gfs(fd, comline->filesystem);
+        do_get_super(fd, &sb);
+        
+        if (comline->no_hidden_file_blocks)
+                hidden_blocks = compute_hidden_blocks(comline, fd);
+
+        do {
+                char *argv[] = { "do_hfile_read", "quota" };
+
+                gi.gi_argc = 2;
+                gi.gi_argv = argv;
+                gi.gi_data = buf;
+                gi.gi_size = sizeof(struct gfs_quota);
+                gi.gi_offset = offset;
+                
+                memset(buf, 0, sizeof(struct gfs_quota));
+                
+                error = ioctl(fd, GFS_IOCTL_SUPER, &gi);
+                if (error < 0)
+                        die("can't read quota file: %s\n",
+                            strerror(errno));
+                
+                gfs_quota_in(&q, buf);
+                
+                id = (offset / sizeof(struct gfs_quota)) >> 1;
+                if (!id && comline->no_hidden_file_blocks)
+                        q.qu_value -= hidden_blocks;
+                
+                if (q.qu_limit || q.qu_warn || q.qu_value)
+                        print_quota(comline, type == GQ_ID_GROUP ? FALSE : TRUE,
+                                    id, &q, &sb);
+
+                offset += 2 * sizeof(struct gfs_quota);
+        } while ((error == sizeof(struct gfs_quota)) && 
+                 (offset < blk_end_offt));
+        
+        close(fd);
+}
+
+void 
+print_quota_file(commandline_t *comline)
+{
+        lblk_range_t lblk_range, *bar;
+        osi_list_t *t, *x;
+
+        lblk_range_list = &lblk_range;
+
+        osi_list_init(&lblk_range_list->list);
+        
+        compute_layout(comline->filesystem);
+        
+        if (osi_list_empty(&lblk_range_list->list)) {
+                /* stuffed quota inode */
+                print_quota_range(comline, GQ_ID_USER, 0, 1);
+                print_quota_range(comline, GQ_ID_GROUP, 0, 1);
+        } else {
+                /* print the user quotas */
+                osi_list_foreach(t, &lblk_range_list->list) {
+                        bar = osi_list_entry(t, lblk_range_t, list);
+                        print_quota_range(comline, GQ_ID_USER, bar->start, 
+                                          bar->len);
+                }
+                /* print the group quotas */
+                osi_list_foreach(t, &lblk_range_list->list) {
+                        bar = osi_list_entry(t, lblk_range_t, list);
+                        print_quota_range(comline, GQ_ID_GROUP, bar->start, 
+                                          bar->len);
+                }
+                /* free the list */
+                osi_list_foreach_safe(t, &lblk_range_list->list, x) {
+                        bar = osi_list_entry(t, lblk_range_t, list);
+                        osi_list_del(&bar->list);
+                        free(bar);
+                }
+        }
+}
+
--- cluster/gfs/gfs_quota/gfs_quota.h	2005/01/04 10:07:09	1.2
+++ cluster/gfs/gfs_quota/gfs_quota.h	2008/01/24 18:29:13	1.2.16.1
@@ -101,4 +101,7 @@
 uint32_t name_to_id(int user, char *name, int numbers);
 char *id_to_name(int user, uint32_t id, int numbers);
 
+/* layout.c */
+
+void print_quota_file(commandline_t *comline);
 #endif /* __GFS_QUOTA_DOT_H__ */
--- cluster/gfs/gfs_quota/main.c	2006/08/21 21:44:28	1.3
+++ cluster/gfs/gfs_quota/main.c	2008/01/24 18:29:13	1.3.2.1
@@ -345,7 +345,7 @@
  *
  */
 
-static void
+void
 print_quota(commandline_t *comline,
 	    int user, uint32_t id,
 	    struct gfs_quota *q,
@@ -402,68 +402,7 @@
 static void
 do_list(commandline_t *comline)
 {
-	int fd;
-	struct gfs_sb sb;
-	struct gfs_ioctl gi;
-	char buf[sizeof(struct gfs_quota)];
-	struct gfs_quota q;
-	uint64_t offset;
-	uint64_t hidden_blocks = 0;
-	uint32_t id;
-	int pass = 0;
-	int error;
-
-	if (!*comline->filesystem)
-		die("need a filesystem to work on\n");
-
-	fd = open(comline->filesystem, O_RDONLY);
-	if (fd < 0)
-		die("can't open file %s: %s\n", comline->filesystem,
-		    strerror(errno));
-
-	check_for_gfs(fd, comline->filesystem);
-	do_get_super(fd, &sb);
-
-	if (comline->no_hidden_file_blocks)
-		hidden_blocks = compute_hidden_blocks(comline, fd);
-
-	for (pass = 0; pass < 2; pass++) {
-		if (!pass)
-			offset = 0;
-		else
-			offset = sizeof(struct gfs_quota);
-
-		do {
-			char *argv[] = { "do_hfile_read", "quota" };
-
-			gi.gi_argc = 2;
-			gi.gi_argv = argv;
-			gi.gi_data = buf;
-			gi.gi_size = sizeof(struct gfs_quota);
-			gi.gi_offset = offset;
-
-			memset(buf, 0, sizeof(struct gfs_quota));
-
-			error = ioctl(fd, GFS_IOCTL_SUPER, &gi);
-			if (error < 0)
-				die("can't read quota file: %s\n",
-				    strerror(errno));
-
-			gfs_quota_in(&q, buf);
-
-			id = (offset / sizeof(struct gfs_quota)) >> 1;
-			if (!id && comline->no_hidden_file_blocks)
-				q.qu_value -= hidden_blocks;
-
-			if (q.qu_limit || q.qu_warn || q.qu_value)
-				print_quota(comline, (pass) ? FALSE : TRUE, id,
-					    &q, &sb);
-
-			offset += 2 * sizeof(struct gfs_quota);
-		} while (error == sizeof(struct gfs_quota));
-	}
-
-	close(fd);
+	print_quota_file(comline);
 }
 
 /**
--- cluster/gfs/gfs_quota/Makefile	2006/08/11 15:18:11	1.5
+++ cluster/gfs/gfs_quota/Makefile	2008/01/24 18:29:13	1.5.2.1
@@ -19,7 +19,8 @@
 	check.c \
 	main.c \
 	names.c \
-	ondisk.c
+	ondisk.c \
+	layout.c
 
 CFLAGS+= -O2 -DHELPER_PROGRAM -D_FILE_OFFSET_BITS=64 \
 	-DGFS_RELEASE_NAME=\"${RELEASE}\"




More information about the Cluster-devel mailing list