diff options
Diffstat (limited to 'fs/gfs2/quota.c')
-rw-r--r-- | fs/gfs2/quota.c | 114 |
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 | */ | ||
572 | static 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); | ||
635 | unlock: | ||
636 | unlock_page(page); | ||
637 | page_cache_release(page); | ||
638 | return err; | ||
639 | } | ||
640 | |||
564 | static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) | 641 | static 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; |