aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/quota.c
diff options
context:
space:
mode:
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;