aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/quota.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-02-08 06:50:51 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2006-02-08 06:50:51 -0500
commit18ec7d5c3f434aed9661ed10a9e1f48cdeb4981d (patch)
treea7161a4c4b3592052e6772e1c23849de16cac649 /fs/gfs2/quota.c
parent257f9b4e97e9a6cceeb247cead92119a4396d37b (diff)
[GFS2] Make journaled data files identical to normal files on disk
This is a very large patch, with a few still to be resolved issues so you might want to check out the previous head of the tree since this is known to be unstable. Fixes for the various bugs will be forthcoming shortly. This patch removes the special data format which has been used up till now for journaled data files. Directories still retain the old format so that they will remain on disk compatible with earlier releases. As a result you can now do the following with journaled data files: 1) mmap them 2) export them over NFS 3) convert to/from normal files whenever you want to (the zero length restriction is gone) In addition the level at which GFS' locking is done has changed for all files (since they all now use the page cache) such that the locking is done at the page cache level rather than the level of the fs operations. This should mean that things like loopback mounts and other things which touch the page cache directly should now work. Current known issues: 1. There is a lock mode inversion problem related to the resource group hold function which needs to be resolved. 2. Any significant amount of I/O causes an oops with an offset of hex 320 (NULL pointer dereference) which appears to be related to a journaled data buffer appearing on a list where it shouldn't be. 3. Direct I/O writes are disabled for the time being (will reappear later) 4. There is probably a deadlock between the page lock and GFS' locks under certain combinations of mmap and fs operation I/O. 5. Issue relating to ref counting on internally used inodes causes a hang on umount (discovered before this patch, and not fixed by it) 6. One part of the directory metadata is different from GFS1 and will need to be resolved before next release. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/quota.c')
-rw-r--r--fs/gfs2/quota.c114
1 files changed, 81 insertions, 33 deletions
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 69e8f4e92e57..138fdf559a9a 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -43,20 +43,22 @@
43#include <linux/buffer_head.h> 43#include <linux/buffer_head.h>
44#include <linux/tty.h> 44#include <linux/tty.h>
45#include <linux/sort.h> 45#include <linux/sort.h>
46#include <linux/fs.h>
46#include <asm/semaphore.h> 47#include <asm/semaphore.h>
47 48
48#include "gfs2.h" 49#include "gfs2.h"
49#include "bmap.h" 50#include "bmap.h"
50#include "glock.h" 51#include "glock.h"
51#include "glops.h" 52#include "glops.h"
52#include "jdata.h"
53#include "log.h" 53#include "log.h"
54#include "meta_io.h" 54#include "meta_io.h"
55#include "quota.h" 55#include "quota.h"
56#include "rgrp.h" 56#include "rgrp.h"
57#include "super.h" 57#include "super.h"
58#include "trans.h" 58#include "trans.h"
59#include "inode.h"
59#include "ops_file.h" 60#include "ops_file.h"
61#include "ops_address.h"
60 62
61#define QUOTA_USER 1 63#define QUOTA_USER 1
62#define QUOTA_GROUP 0 64#define QUOTA_GROUP 0
@@ -561,6 +563,81 @@ static void do_qc(struct gfs2_quota_data *qd, int64_t change)
561 up(&sdp->sd_quota_mutex); 563 up(&sdp->sd_quota_mutex);
562} 564}
563 565
566/**
567 * gfs2_adjust_quota
568 *
569 * This function was mostly borrowed from gfs2_block_truncate_page which was
570 * in turn mostly borrowed from ext3
571 */
572static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
573 int64_t change, struct gfs2_quota_data *qd)
574{
575 struct inode *inode = gfs2_ip2v(ip);
576 struct address_space *mapping = inode->i_mapping;
577 unsigned long index = loc >> PAGE_CACHE_SHIFT;
578 unsigned offset = loc & (PAGE_CACHE_SHIFT - 1);
579 unsigned blocksize, iblock, pos;
580 struct buffer_head *bh;
581 struct page *page;
582 void *kaddr;
583 __be64 *ptr;
584 u64 value;
585 int err = -EIO;
586
587 page = grab_cache_page(mapping, index);
588 if (!page)
589 return -ENOMEM;
590
591 blocksize = inode->i_sb->s_blocksize;
592 iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
593
594 if (!page_has_buffers(page))
595 create_empty_buffers(page, blocksize, 0);
596
597 bh = page_buffers(page);
598 pos = blocksize;
599 while (offset >= pos) {
600 bh = bh->b_this_page;
601 iblock++;
602 pos += blocksize;
603 }
604
605 if (!buffer_mapped(bh)) {
606 gfs2_get_block(inode, iblock, bh, 1);
607 if (!buffer_mapped(bh))
608 goto unlock;
609 }
610
611 if (PageUptodate(page))
612 set_buffer_uptodate(bh);
613
614 if (!buffer_uptodate(bh)) {
615 ll_rw_block(READ, 1, &bh);
616 wait_on_buffer(bh);
617 if (!buffer_uptodate(bh))
618 goto unlock;
619 }
620
621 gfs2_trans_add_bh(ip->i_gl, bh, 0);
622
623 kaddr = kmap_atomic(page, KM_USER0);
624 ptr = (__be64 *)(kaddr + offset);
625 value = *ptr = cpu_to_be64(be64_to_cpu(*ptr) + change);
626 flush_dcache_page(page);
627 kunmap_atomic(kaddr, KM_USER0);
628 err = 0;
629 qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC);
630#if 0
631 qd->qd_qb.qb_limit = cpu_to_be64(q.qu_limit);
632 qd->qd_qb.qb_warn = cpu_to_be64(q.qu_warn);
633#endif
634 qd->qd_qb.qb_value = cpu_to_be64(value);
635unlock:
636 unlock_page(page);
637 page_cache_release(page);
638 return err;
639}
640
564static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) 641static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
565{ 642{
566 struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd; 643 struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd;
@@ -635,43 +712,14 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
635 712
636 file_ra_state_init(&ra_state, ip->i_vnode->i_mapping); 713 file_ra_state_init(&ra_state, ip->i_vnode->i_mapping);
637 for (x = 0; x < num_qd; x++) { 714 for (x = 0; x < num_qd; x++) {
638 char buf[sizeof(struct gfs2_quota)];
639 struct gfs2_quota q;
640
641 qd = qda[x]; 715 qd = qda[x];
642 offset = qd2offset(qd); 716 offset = qd2offset(qd);
643 717 error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync,
644 /* The quota file may not be a multiple of 718 (struct gfs2_quota_data *)qd->qd_gl->gl_lvb);
645 sizeof(struct gfs2_quota) bytes. */ 719 if (error)
646 memset(buf, 0, sizeof(struct gfs2_quota));
647
648 error = gfs2_internal_read(ip, &ra_state, buf, &offset,
649 sizeof(struct gfs2_quota));
650 if (error < 0)
651 goto out_end_trans; 720 goto out_end_trans;
652 721
653 gfs2_quota_in(&q, buf);
654 q.qu_value += qda[x]->qd_change_sync;
655 gfs2_quota_out(&q, buf);
656
657 error = gfs2_jdata_write_mem(ip, buf, offset,
658 sizeof(struct gfs2_quota));
659 if (error < 0)
660 goto out_end_trans;
661 else if (error != sizeof(struct gfs2_quota)) {
662 error = -EIO;
663 goto out_end_trans;
664 }
665
666 do_qc(qd, -qd->qd_change_sync); 722 do_qc(qd, -qd->qd_change_sync);
667
668 memset(&qd->qd_qb, 0, sizeof(struct gfs2_quota_lvb));
669 qd->qd_qb.qb_magic = GFS2_MAGIC;
670 qd->qd_qb.qb_limit = q.qu_limit;
671 qd->qd_qb.qb_warn = q.qu_warn;
672 qd->qd_qb.qb_value = q.qu_value;
673
674 gfs2_quota_lvb_out(&qd->qd_qb, qd->qd_gl->gl_lvb);
675 } 723 }
676 724
677 error = 0; 725 error = 0;