diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 11:58:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 11:58:43 -0400 |
commit | 3ae2a1ce2e7b70254e5c9e465adefac9cba191d6 (patch) | |
tree | 388da81c97a92861b84b408eb12a494d859cca7a /fs/gfs2 | |
parent | 26a992dbc24e34cbdd03621d1c97ce571ad74e65 (diff) | |
parent | 7e32d02613a72a39ba01638337c609a9a866c653 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw:
GFS2: Don't use _raw version of RCU dereference
GFS2: Adding missing unlock_page()
GFS2: Update to AIL list locking
GFS2: introduce AIL lock
GFS2: fix block allocation check for fallocate
GFS2: Optimize glock multiple-dequeue code
GFS2: Remove potential race in flock code
GFS2: Fix glock deallocation race
GFS2: quota allows exceeding hard limit
GFS2: deallocation performance patch
GFS2: panics on quotacheck update
GFS2: Improve cluster mmap scalability
GFS2: Fix glock queue trace point
GFS2: Post-VFS scale update for RCU path walk
GFS2: Use RCU for glock hash table
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/acl.c | 7 | ||||
-rw-r--r-- | fs/gfs2/aops.c | 1 | ||||
-rw-r--r-- | fs/gfs2/bmap.c | 20 | ||||
-rw-r--r-- | fs/gfs2/file.c | 77 | ||||
-rw-r--r-- | fs/gfs2/glock.c | 410 | ||||
-rw-r--r-- | fs/gfs2/glock.h | 39 | ||||
-rw-r--r-- | fs/gfs2/glops.c | 33 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 7 | ||||
-rw-r--r-- | fs/gfs2/lock_dlm.c | 14 | ||||
-rw-r--r-- | fs/gfs2/log.c | 32 | ||||
-rw-r--r-- | fs/gfs2/lops.c | 10 | ||||
-rw-r--r-- | fs/gfs2/main.c | 6 | ||||
-rw-r--r-- | fs/gfs2/meta_io.c | 2 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 11 | ||||
-rw-r--r-- | fs/gfs2/ops_inode.c | 10 | ||||
-rw-r--r-- | fs/gfs2/quota.c | 14 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 34 | ||||
-rw-r--r-- | fs/gfs2/rgrp.h | 2 |
18 files changed, 351 insertions, 378 deletions
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 7118f1a780a..cbc07155b1a 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c | |||
@@ -80,8 +80,11 @@ int gfs2_check_acl(struct inode *inode, int mask, unsigned int flags) | |||
80 | struct posix_acl *acl; | 80 | struct posix_acl *acl; |
81 | int error; | 81 | int error; |
82 | 82 | ||
83 | if (flags & IPERM_FLAG_RCU) | 83 | if (flags & IPERM_FLAG_RCU) { |
84 | return -ECHILD; | 84 | if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) |
85 | return -ECHILD; | ||
86 | return -EAGAIN; | ||
87 | } | ||
85 | 88 | ||
86 | acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS); | 89 | acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS); |
87 | if (IS_ERR(acl)) | 90 | if (IS_ERR(acl)) |
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 4f36f8832b9..aad77e4f61b 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c | |||
@@ -695,6 +695,7 @@ out: | |||
695 | if (error == 0) | 695 | if (error == 0) |
696 | return 0; | 696 | return 0; |
697 | 697 | ||
698 | unlock_page(page); | ||
698 | page_cache_release(page); | 699 | page_cache_release(page); |
699 | 700 | ||
700 | gfs2_trans_end(sdp); | 701 | gfs2_trans_end(sdp); |
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 3c4039d5eef..ef3dc4b9fae 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "meta_io.h" | 21 | #include "meta_io.h" |
22 | #include "quota.h" | 22 | #include "quota.h" |
23 | #include "rgrp.h" | 23 | #include "rgrp.h" |
24 | #include "super.h" | ||
24 | #include "trans.h" | 25 | #include "trans.h" |
25 | #include "dir.h" | 26 | #include "dir.h" |
26 | #include "util.h" | 27 | #include "util.h" |
@@ -757,7 +758,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
757 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 758 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
758 | struct gfs2_rgrp_list rlist; | 759 | struct gfs2_rgrp_list rlist; |
759 | u64 bn, bstart; | 760 | u64 bn, bstart; |
760 | u32 blen; | 761 | u32 blen, btotal; |
761 | __be64 *p; | 762 | __be64 *p; |
762 | unsigned int rg_blocks = 0; | 763 | unsigned int rg_blocks = 0; |
763 | int metadata; | 764 | int metadata; |
@@ -839,6 +840,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
839 | 840 | ||
840 | bstart = 0; | 841 | bstart = 0; |
841 | blen = 0; | 842 | blen = 0; |
843 | btotal = 0; | ||
842 | 844 | ||
843 | for (p = top; p < bottom; p++) { | 845 | for (p = top; p < bottom; p++) { |
844 | if (!*p) | 846 | if (!*p) |
@@ -851,9 +853,11 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
851 | else { | 853 | else { |
852 | if (bstart) { | 854 | if (bstart) { |
853 | if (metadata) | 855 | if (metadata) |
854 | gfs2_free_meta(ip, bstart, blen); | 856 | __gfs2_free_meta(ip, bstart, blen); |
855 | else | 857 | else |
856 | gfs2_free_data(ip, bstart, blen); | 858 | __gfs2_free_data(ip, bstart, blen); |
859 | |||
860 | btotal += blen; | ||
857 | } | 861 | } |
858 | 862 | ||
859 | bstart = bn; | 863 | bstart = bn; |
@@ -865,11 +869,17 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
865 | } | 869 | } |
866 | if (bstart) { | 870 | if (bstart) { |
867 | if (metadata) | 871 | if (metadata) |
868 | gfs2_free_meta(ip, bstart, blen); | 872 | __gfs2_free_meta(ip, bstart, blen); |
869 | else | 873 | else |
870 | gfs2_free_data(ip, bstart, blen); | 874 | __gfs2_free_data(ip, bstart, blen); |
875 | |||
876 | btotal += blen; | ||
871 | } | 877 | } |
872 | 878 | ||
879 | gfs2_statfs_change(sdp, 0, +btotal, 0); | ||
880 | gfs2_quota_change(ip, -(s64)btotal, ip->i_inode.i_uid, | ||
881 | ip->i_inode.i_gid); | ||
882 | |||
873 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | 883 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; |
874 | 884 | ||
875 | gfs2_dinode_out(ip, dibh->b_data); | 885 | gfs2_dinode_out(ip, dibh->b_data); |
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 7cfdcb91336..4074b952b05 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -448,15 +448,20 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) | |||
448 | { | 448 | { |
449 | struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); | 449 | struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); |
450 | 450 | ||
451 | if (!(file->f_flags & O_NOATIME)) { | 451 | if (!(file->f_flags & O_NOATIME) && |
452 | !IS_NOATIME(&ip->i_inode)) { | ||
452 | struct gfs2_holder i_gh; | 453 | struct gfs2_holder i_gh; |
453 | int error; | 454 | int error; |
454 | 455 | ||
455 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | 456 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
456 | error = gfs2_glock_nq(&i_gh); | 457 | error = gfs2_glock_nq(&i_gh); |
457 | file_accessed(file); | 458 | if (error == 0) { |
458 | if (error == 0) | 459 | file_accessed(file); |
459 | gfs2_glock_dq_uninit(&i_gh); | 460 | gfs2_glock_dq(&i_gh); |
461 | } | ||
462 | gfs2_holder_uninit(&i_gh); | ||
463 | if (error) | ||
464 | return error; | ||
460 | } | 465 | } |
461 | vma->vm_ops = &gfs2_vm_ops; | 466 | vma->vm_ops = &gfs2_vm_ops; |
462 | vma->vm_flags |= VM_CAN_NONLINEAR; | 467 | vma->vm_flags |= VM_CAN_NONLINEAR; |
@@ -617,8 +622,7 @@ static void empty_write_end(struct page *page, unsigned from, | |||
617 | { | 622 | { |
618 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); | 623 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); |
619 | 624 | ||
620 | page_zero_new_buffers(page, from, to); | 625 | zero_user(page, from, to-from); |
621 | flush_dcache_page(page); | ||
622 | mark_page_accessed(page); | 626 | mark_page_accessed(page); |
623 | 627 | ||
624 | if (!gfs2_is_writeback(ip)) | 628 | if (!gfs2_is_writeback(ip)) |
@@ -627,36 +631,43 @@ static void empty_write_end(struct page *page, unsigned from, | |||
627 | block_commit_write(page, from, to); | 631 | block_commit_write(page, from, to); |
628 | } | 632 | } |
629 | 633 | ||
630 | static int write_empty_blocks(struct page *page, unsigned from, unsigned to) | 634 | static int needs_empty_write(sector_t block, struct inode *inode) |
631 | { | 635 | { |
632 | unsigned start, end, next; | ||
633 | struct buffer_head *bh, *head; | ||
634 | int error; | 636 | int error; |
637 | struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; | ||
635 | 638 | ||
636 | if (!page_has_buffers(page)) { | 639 | bh_map.b_size = 1 << inode->i_blkbits; |
637 | error = __block_write_begin(page, from, to - from, gfs2_block_map); | 640 | error = gfs2_block_map(inode, block, &bh_map, 0); |
638 | if (unlikely(error)) | 641 | if (unlikely(error)) |
639 | return error; | 642 | return error; |
643 | return !buffer_mapped(&bh_map); | ||
644 | } | ||
640 | 645 | ||
641 | empty_write_end(page, from, to); | 646 | static int write_empty_blocks(struct page *page, unsigned from, unsigned to) |
642 | return 0; | 647 | { |
643 | } | 648 | struct inode *inode = page->mapping->host; |
649 | unsigned start, end, next, blksize; | ||
650 | sector_t block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
651 | int ret; | ||
644 | 652 | ||
645 | bh = head = page_buffers(page); | 653 | blksize = 1 << inode->i_blkbits; |
646 | next = end = 0; | 654 | next = end = 0; |
647 | while (next < from) { | 655 | while (next < from) { |
648 | next += bh->b_size; | 656 | next += blksize; |
649 | bh = bh->b_this_page; | 657 | block++; |
650 | } | 658 | } |
651 | start = next; | 659 | start = next; |
652 | do { | 660 | do { |
653 | next += bh->b_size; | 661 | next += blksize; |
654 | if (buffer_mapped(bh)) { | 662 | ret = needs_empty_write(block, inode); |
663 | if (unlikely(ret < 0)) | ||
664 | return ret; | ||
665 | if (ret == 0) { | ||
655 | if (end) { | 666 | if (end) { |
656 | error = __block_write_begin(page, start, end - start, | 667 | ret = __block_write_begin(page, start, end - start, |
657 | gfs2_block_map); | 668 | gfs2_block_map); |
658 | if (unlikely(error)) | 669 | if (unlikely(ret)) |
659 | return error; | 670 | return ret; |
660 | empty_write_end(page, start, end); | 671 | empty_write_end(page, start, end); |
661 | end = 0; | 672 | end = 0; |
662 | } | 673 | } |
@@ -664,13 +675,13 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to) | |||
664 | } | 675 | } |
665 | else | 676 | else |
666 | end = next; | 677 | end = next; |
667 | bh = bh->b_this_page; | 678 | block++; |
668 | } while (next < to); | 679 | } while (next < to); |
669 | 680 | ||
670 | if (end) { | 681 | if (end) { |
671 | error = __block_write_begin(page, start, end - start, gfs2_block_map); | 682 | ret = __block_write_begin(page, start, end - start, gfs2_block_map); |
672 | if (unlikely(error)) | 683 | if (unlikely(ret)) |
673 | return error; | 684 | return ret; |
674 | empty_write_end(page, start, end); | 685 | empty_write_end(page, start, end); |
675 | } | 686 | } |
676 | 687 | ||
@@ -976,8 +987,10 @@ static void do_unflock(struct file *file, struct file_lock *fl) | |||
976 | 987 | ||
977 | mutex_lock(&fp->f_fl_mutex); | 988 | mutex_lock(&fp->f_fl_mutex); |
978 | flock_lock_file_wait(file, fl); | 989 | flock_lock_file_wait(file, fl); |
979 | if (fl_gh->gh_gl) | 990 | if (fl_gh->gh_gl) { |
980 | gfs2_glock_dq_uninit(fl_gh); | 991 | gfs2_glock_dq_wait(fl_gh); |
992 | gfs2_holder_uninit(fl_gh); | ||
993 | } | ||
981 | mutex_unlock(&fp->f_fl_mutex); | 994 | mutex_unlock(&fp->f_fl_mutex); |
982 | } | 995 | } |
983 | 996 | ||
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 7cd9a5a68d5..e2431313491 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -26,6 +26,9 @@ | |||
26 | #include <linux/freezer.h> | 26 | #include <linux/freezer.h> |
27 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
28 | #include <linux/jiffies.h> | 28 | #include <linux/jiffies.h> |
29 | #include <linux/rcupdate.h> | ||
30 | #include <linux/rculist_bl.h> | ||
31 | #include <linux/bit_spinlock.h> | ||
29 | 32 | ||
30 | #include "gfs2.h" | 33 | #include "gfs2.h" |
31 | #include "incore.h" | 34 | #include "incore.h" |
@@ -41,10 +44,6 @@ | |||
41 | #define CREATE_TRACE_POINTS | 44 | #define CREATE_TRACE_POINTS |
42 | #include "trace_gfs2.h" | 45 | #include "trace_gfs2.h" |
43 | 46 | ||
44 | struct gfs2_gl_hash_bucket { | ||
45 | struct hlist_head hb_list; | ||
46 | }; | ||
47 | |||
48 | struct gfs2_glock_iter { | 47 | struct gfs2_glock_iter { |
49 | int hash; /* hash bucket index */ | 48 | int hash; /* hash bucket index */ |
50 | struct gfs2_sbd *sdp; /* incore superblock */ | 49 | struct gfs2_sbd *sdp; /* incore superblock */ |
@@ -54,7 +53,6 @@ struct gfs2_glock_iter { | |||
54 | 53 | ||
55 | typedef void (*glock_examiner) (struct gfs2_glock * gl); | 54 | typedef void (*glock_examiner) (struct gfs2_glock * gl); |
56 | 55 | ||
57 | static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); | ||
58 | static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl); | 56 | static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl); |
59 | #define GLOCK_BUG_ON(gl,x) do { if (unlikely(x)) { __dump_glock(NULL, gl); BUG(); } } while(0) | 57 | #define GLOCK_BUG_ON(gl,x) do { if (unlikely(x)) { __dump_glock(NULL, gl); BUG(); } } while(0) |
60 | static void do_xmote(struct gfs2_glock *gl, struct gfs2_holder *gh, unsigned int target); | 58 | static void do_xmote(struct gfs2_glock *gl, struct gfs2_holder *gh, unsigned int target); |
@@ -70,57 +68,9 @@ static DEFINE_SPINLOCK(lru_lock); | |||
70 | #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) | 68 | #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) |
71 | #define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1) | 69 | #define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1) |
72 | 70 | ||
73 | static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE]; | 71 | static struct hlist_bl_head gl_hash_table[GFS2_GL_HASH_SIZE]; |
74 | static struct dentry *gfs2_root; | 72 | static struct dentry *gfs2_root; |
75 | 73 | ||
76 | /* | ||
77 | * Despite what you might think, the numbers below are not arbitrary :-) | ||
78 | * They are taken from the ipv4 routing hash code, which is well tested | ||
79 | * and thus should be nearly optimal. Later on we might tweek the numbers | ||
80 | * but for now this should be fine. | ||
81 | * | ||
82 | * The reason for putting the locks in a separate array from the list heads | ||
83 | * is that we can have fewer locks than list heads and save memory. We use | ||
84 | * the same hash function for both, but with a different hash mask. | ||
85 | */ | ||
86 | #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \ | ||
87 | defined(CONFIG_PROVE_LOCKING) | ||
88 | |||
89 | #ifdef CONFIG_LOCKDEP | ||
90 | # define GL_HASH_LOCK_SZ 256 | ||
91 | #else | ||
92 | # if NR_CPUS >= 32 | ||
93 | # define GL_HASH_LOCK_SZ 4096 | ||
94 | # elif NR_CPUS >= 16 | ||
95 | # define GL_HASH_LOCK_SZ 2048 | ||
96 | # elif NR_CPUS >= 8 | ||
97 | # define GL_HASH_LOCK_SZ 1024 | ||
98 | # elif NR_CPUS >= 4 | ||
99 | # define GL_HASH_LOCK_SZ 512 | ||
100 | # else | ||
101 | # define GL_HASH_LOCK_SZ 256 | ||
102 | # endif | ||
103 | #endif | ||
104 | |||
105 | /* We never want more locks than chains */ | ||
106 | #if GFS2_GL_HASH_SIZE < GL_HASH_LOCK_SZ | ||
107 | # undef GL_HASH_LOCK_SZ | ||
108 | # define GL_HASH_LOCK_SZ GFS2_GL_HASH_SIZE | ||
109 | #endif | ||
110 | |||
111 | static rwlock_t gl_hash_locks[GL_HASH_LOCK_SZ]; | ||
112 | |||
113 | static inline rwlock_t *gl_lock_addr(unsigned int x) | ||
114 | { | ||
115 | return &gl_hash_locks[x & (GL_HASH_LOCK_SZ-1)]; | ||
116 | } | ||
117 | #else /* not SMP, so no spinlocks required */ | ||
118 | static inline rwlock_t *gl_lock_addr(unsigned int x) | ||
119 | { | ||
120 | return NULL; | ||
121 | } | ||
122 | #endif | ||
123 | |||
124 | /** | 74 | /** |
125 | * gl_hash() - Turn glock number into hash bucket number | 75 | * gl_hash() - Turn glock number into hash bucket number |
126 | * @lock: The glock number | 76 | * @lock: The glock number |
@@ -141,25 +91,35 @@ static unsigned int gl_hash(const struct gfs2_sbd *sdp, | |||
141 | return h; | 91 | return h; |
142 | } | 92 | } |
143 | 93 | ||
144 | /** | 94 | static inline void spin_lock_bucket(unsigned int hash) |
145 | * glock_free() - Perform a few checks and then release struct gfs2_glock | 95 | { |
146 | * @gl: The glock to release | 96 | struct hlist_bl_head *bl = &gl_hash_table[hash]; |
147 | * | 97 | bit_spin_lock(0, (unsigned long *)bl); |
148 | * Also calls lock module to release its internal structure for this glock. | 98 | } |
149 | * | ||
150 | */ | ||
151 | 99 | ||
152 | static void glock_free(struct gfs2_glock *gl) | 100 | static inline void spin_unlock_bucket(unsigned int hash) |
101 | { | ||
102 | struct hlist_bl_head *bl = &gl_hash_table[hash]; | ||
103 | __bit_spin_unlock(0, (unsigned long *)bl); | ||
104 | } | ||
105 | |||
106 | static void gfs2_glock_dealloc(struct rcu_head *rcu) | ||
107 | { | ||
108 | struct gfs2_glock *gl = container_of(rcu, struct gfs2_glock, gl_rcu); | ||
109 | |||
110 | if (gl->gl_ops->go_flags & GLOF_ASPACE) | ||
111 | kmem_cache_free(gfs2_glock_aspace_cachep, gl); | ||
112 | else | ||
113 | kmem_cache_free(gfs2_glock_cachep, gl); | ||
114 | } | ||
115 | |||
116 | void gfs2_glock_free(struct gfs2_glock *gl) | ||
153 | { | 117 | { |
154 | struct gfs2_sbd *sdp = gl->gl_sbd; | 118 | struct gfs2_sbd *sdp = gl->gl_sbd; |
155 | struct address_space *mapping = gfs2_glock2aspace(gl); | ||
156 | struct kmem_cache *cachep = gfs2_glock_cachep; | ||
157 | 119 | ||
158 | GLOCK_BUG_ON(gl, mapping && mapping->nrpages); | 120 | call_rcu(&gl->gl_rcu, gfs2_glock_dealloc); |
159 | trace_gfs2_glock_put(gl); | 121 | if (atomic_dec_and_test(&sdp->sd_glock_disposal)) |
160 | if (mapping) | 122 | wake_up(&sdp->sd_glock_wait); |
161 | cachep = gfs2_glock_aspace_cachep; | ||
162 | sdp->sd_lockstruct.ls_ops->lm_put_lock(cachep, gl); | ||
163 | } | 123 | } |
164 | 124 | ||
165 | /** | 125 | /** |
@@ -185,34 +145,49 @@ static int demote_ok(const struct gfs2_glock *gl) | |||
185 | { | 145 | { |
186 | const struct gfs2_glock_operations *glops = gl->gl_ops; | 146 | const struct gfs2_glock_operations *glops = gl->gl_ops; |
187 | 147 | ||
148 | /* assert_spin_locked(&gl->gl_spin); */ | ||
149 | |||
188 | if (gl->gl_state == LM_ST_UNLOCKED) | 150 | if (gl->gl_state == LM_ST_UNLOCKED) |
189 | return 0; | 151 | return 0; |
190 | if (!list_empty(&gl->gl_holders)) | 152 | if (test_bit(GLF_LFLUSH, &gl->gl_flags)) |
153 | return 0; | ||
154 | if ((gl->gl_name.ln_type != LM_TYPE_INODE) && | ||
155 | !list_empty(&gl->gl_holders)) | ||
191 | return 0; | 156 | return 0; |
192 | if (glops->go_demote_ok) | 157 | if (glops->go_demote_ok) |
193 | return glops->go_demote_ok(gl); | 158 | return glops->go_demote_ok(gl); |
194 | return 1; | 159 | return 1; |
195 | } | 160 | } |
196 | 161 | ||
162 | |||
197 | /** | 163 | /** |
198 | * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list | 164 | * __gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list |
199 | * @gl: the glock | 165 | * @gl: the glock |
200 | * | 166 | * |
167 | * If the glock is demotable, then we add it (or move it) to the end | ||
168 | * of the glock LRU list. | ||
201 | */ | 169 | */ |
202 | 170 | ||
203 | static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) | 171 | static void __gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) |
204 | { | 172 | { |
205 | int may_reclaim; | 173 | if (demote_ok(gl)) { |
206 | may_reclaim = (demote_ok(gl) && | 174 | spin_lock(&lru_lock); |
207 | (atomic_read(&gl->gl_ref) == 1 || | 175 | |
208 | (gl->gl_name.ln_type == LM_TYPE_INODE && | 176 | if (!list_empty(&gl->gl_lru)) |
209 | atomic_read(&gl->gl_ref) <= 2))); | 177 | list_del_init(&gl->gl_lru); |
210 | spin_lock(&lru_lock); | 178 | else |
211 | if (list_empty(&gl->gl_lru) && may_reclaim) { | 179 | atomic_inc(&lru_count); |
180 | |||
212 | list_add_tail(&gl->gl_lru, &lru_list); | 181 | list_add_tail(&gl->gl_lru, &lru_list); |
213 | atomic_inc(&lru_count); | 182 | spin_unlock(&lru_lock); |
214 | } | 183 | } |
215 | spin_unlock(&lru_lock); | 184 | } |
185 | |||
186 | void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) | ||
187 | { | ||
188 | spin_lock(&gl->gl_spin); | ||
189 | __gfs2_glock_schedule_for_reclaim(gl); | ||
190 | spin_unlock(&gl->gl_spin); | ||
216 | } | 191 | } |
217 | 192 | ||
218 | /** | 193 | /** |
@@ -227,7 +202,6 @@ void gfs2_glock_put_nolock(struct gfs2_glock *gl) | |||
227 | { | 202 | { |
228 | if (atomic_dec_and_test(&gl->gl_ref)) | 203 | if (atomic_dec_and_test(&gl->gl_ref)) |
229 | GLOCK_BUG_ON(gl, 1); | 204 | GLOCK_BUG_ON(gl, 1); |
230 | gfs2_glock_schedule_for_reclaim(gl); | ||
231 | } | 205 | } |
232 | 206 | ||
233 | /** | 207 | /** |
@@ -236,30 +210,26 @@ void gfs2_glock_put_nolock(struct gfs2_glock *gl) | |||
236 | * | 210 | * |
237 | */ | 211 | */ |
238 | 212 | ||
239 | int gfs2_glock_put(struct gfs2_glock *gl) | 213 | void gfs2_glock_put(struct gfs2_glock *gl) |
240 | { | 214 | { |
241 | int rv = 0; | 215 | struct gfs2_sbd *sdp = gl->gl_sbd; |
216 | struct address_space *mapping = gfs2_glock2aspace(gl); | ||
242 | 217 | ||
243 | write_lock(gl_lock_addr(gl->gl_hash)); | 218 | if (atomic_dec_and_test(&gl->gl_ref)) { |
244 | if (atomic_dec_and_lock(&gl->gl_ref, &lru_lock)) { | 219 | spin_lock_bucket(gl->gl_hash); |
245 | hlist_del(&gl->gl_list); | 220 | hlist_bl_del_rcu(&gl->gl_list); |
221 | spin_unlock_bucket(gl->gl_hash); | ||
222 | spin_lock(&lru_lock); | ||
246 | if (!list_empty(&gl->gl_lru)) { | 223 | if (!list_empty(&gl->gl_lru)) { |
247 | list_del_init(&gl->gl_lru); | 224 | list_del_init(&gl->gl_lru); |
248 | atomic_dec(&lru_count); | 225 | atomic_dec(&lru_count); |
249 | } | 226 | } |
250 | spin_unlock(&lru_lock); | 227 | spin_unlock(&lru_lock); |
251 | write_unlock(gl_lock_addr(gl->gl_hash)); | ||
252 | GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); | 228 | GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); |
253 | glock_free(gl); | 229 | GLOCK_BUG_ON(gl, mapping && mapping->nrpages); |
254 | rv = 1; | 230 | trace_gfs2_glock_put(gl); |
255 | goto out; | 231 | sdp->sd_lockstruct.ls_ops->lm_put_lock(gl); |
256 | } | 232 | } |
257 | spin_lock(&gl->gl_spin); | ||
258 | gfs2_glock_schedule_for_reclaim(gl); | ||
259 | spin_unlock(&gl->gl_spin); | ||
260 | write_unlock(gl_lock_addr(gl->gl_hash)); | ||
261 | out: | ||
262 | return rv; | ||
263 | } | 233 | } |
264 | 234 | ||
265 | /** | 235 | /** |
@@ -275,17 +245,15 @@ static struct gfs2_glock *search_bucket(unsigned int hash, | |||
275 | const struct lm_lockname *name) | 245 | const struct lm_lockname *name) |
276 | { | 246 | { |
277 | struct gfs2_glock *gl; | 247 | struct gfs2_glock *gl; |
278 | struct hlist_node *h; | 248 | struct hlist_bl_node *h; |
279 | 249 | ||
280 | hlist_for_each_entry(gl, h, &gl_hash_table[hash].hb_list, gl_list) { | 250 | hlist_bl_for_each_entry_rcu(gl, h, &gl_hash_table[hash], gl_list) { |
281 | if (!lm_name_equal(&gl->gl_name, name)) | 251 | if (!lm_name_equal(&gl->gl_name, name)) |
282 | continue; | 252 | continue; |
283 | if (gl->gl_sbd != sdp) | 253 | if (gl->gl_sbd != sdp) |
284 | continue; | 254 | continue; |
285 | 255 | if (atomic_inc_not_zero(&gl->gl_ref)) | |
286 | atomic_inc(&gl->gl_ref); | 256 | return gl; |
287 | |||
288 | return gl; | ||
289 | } | 257 | } |
290 | 258 | ||
291 | return NULL; | 259 | return NULL; |
@@ -743,10 +711,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, | |||
743 | struct gfs2_glock *gl, *tmp; | 711 | struct gfs2_glock *gl, *tmp; |
744 | unsigned int hash = gl_hash(sdp, &name); | 712 | unsigned int hash = gl_hash(sdp, &name); |
745 | struct address_space *mapping; | 713 | struct address_space *mapping; |
714 | struct kmem_cache *cachep; | ||
746 | 715 | ||
747 | read_lock(gl_lock_addr(hash)); | 716 | rcu_read_lock(); |
748 | gl = search_bucket(hash, sdp, &name); | 717 | gl = search_bucket(hash, sdp, &name); |
749 | read_unlock(gl_lock_addr(hash)); | 718 | rcu_read_unlock(); |
750 | 719 | ||
751 | *glp = gl; | 720 | *glp = gl; |
752 | if (gl) | 721 | if (gl) |
@@ -755,9 +724,10 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, | |||
755 | return -ENOENT; | 724 | return -ENOENT; |
756 | 725 | ||
757 | if (glops->go_flags & GLOF_ASPACE) | 726 | if (glops->go_flags & GLOF_ASPACE) |
758 | gl = kmem_cache_alloc(gfs2_glock_aspace_cachep, GFP_KERNEL); | 727 | cachep = gfs2_glock_aspace_cachep; |
759 | else | 728 | else |
760 | gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL); | 729 | cachep = gfs2_glock_cachep; |
730 | gl = kmem_cache_alloc(cachep, GFP_KERNEL); | ||
761 | if (!gl) | 731 | if (!gl) |
762 | return -ENOMEM; | 732 | return -ENOMEM; |
763 | 733 | ||
@@ -790,15 +760,16 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, | |||
790 | mapping->writeback_index = 0; | 760 | mapping->writeback_index = 0; |
791 | } | 761 | } |
792 | 762 | ||
793 | write_lock(gl_lock_addr(hash)); | 763 | spin_lock_bucket(hash); |
794 | tmp = search_bucket(hash, sdp, &name); | 764 | tmp = search_bucket(hash, sdp, &name); |
795 | if (tmp) { | 765 | if (tmp) { |
796 | write_unlock(gl_lock_addr(hash)); | 766 | spin_unlock_bucket(hash); |
797 | glock_free(gl); | 767 | kmem_cache_free(cachep, gl); |
768 | atomic_dec(&sdp->sd_glock_disposal); | ||
798 | gl = tmp; | 769 | gl = tmp; |
799 | } else { | 770 | } else { |
800 | hlist_add_head(&gl->gl_list, &gl_hash_table[hash].hb_list); | 771 | hlist_bl_add_head_rcu(&gl->gl_list, &gl_hash_table[hash]); |
801 | write_unlock(gl_lock_addr(hash)); | 772 | spin_unlock_bucket(hash); |
802 | } | 773 | } |
803 | 774 | ||
804 | *glp = gl; | 775 | *glp = gl; |
@@ -1007,13 +978,13 @@ fail: | |||
1007 | insert_pt = &gh2->gh_list; | 978 | insert_pt = &gh2->gh_list; |
1008 | } | 979 | } |
1009 | set_bit(GLF_QUEUED, &gl->gl_flags); | 980 | set_bit(GLF_QUEUED, &gl->gl_flags); |
981 | trace_gfs2_glock_queue(gh, 1); | ||
1010 | if (likely(insert_pt == NULL)) { | 982 | if (likely(insert_pt == NULL)) { |
1011 | list_add_tail(&gh->gh_list, &gl->gl_holders); | 983 | list_add_tail(&gh->gh_list, &gl->gl_holders); |
1012 | if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY)) | 984 | if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY)) |
1013 | goto do_cancel; | 985 | goto do_cancel; |
1014 | return; | 986 | return; |
1015 | } | 987 | } |
1016 | trace_gfs2_glock_queue(gh, 1); | ||
1017 | list_add_tail(&gh->gh_list, insert_pt); | 988 | list_add_tail(&gh->gh_list, insert_pt); |
1018 | do_cancel: | 989 | do_cancel: |
1019 | gh = list_entry(gl->gl_holders.next, struct gfs2_holder, gh_list); | 990 | gh = list_entry(gl->gl_holders.next, struct gfs2_holder, gh_list); |
@@ -1113,6 +1084,7 @@ void gfs2_glock_dq(struct gfs2_holder *gh) | |||
1113 | !test_bit(GLF_DEMOTE, &gl->gl_flags)) | 1084 | !test_bit(GLF_DEMOTE, &gl->gl_flags)) |
1114 | fast_path = 1; | 1085 | fast_path = 1; |
1115 | } | 1086 | } |
1087 | __gfs2_glock_schedule_for_reclaim(gl); | ||
1116 | trace_gfs2_glock_queue(gh, 0); | 1088 | trace_gfs2_glock_queue(gh, 0); |
1117 | spin_unlock(&gl->gl_spin); | 1089 | spin_unlock(&gl->gl_spin); |
1118 | if (likely(fast_path)) | 1090 | if (likely(fast_path)) |
@@ -1276,10 +1248,8 @@ int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs) | |||
1276 | 1248 | ||
1277 | void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs) | 1249 | void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs) |
1278 | { | 1250 | { |
1279 | unsigned int x; | 1251 | while (num_gh--) |
1280 | 1252 | gfs2_glock_dq(&ghs[num_gh]); | |
1281 | for (x = 0; x < num_gh; x++) | ||
1282 | gfs2_glock_dq(&ghs[x]); | ||
1283 | } | 1253 | } |
1284 | 1254 | ||
1285 | /** | 1255 | /** |
@@ -1291,10 +1261,8 @@ void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs) | |||
1291 | 1261 | ||
1292 | void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs) | 1262 | void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs) |
1293 | { | 1263 | { |
1294 | unsigned int x; | 1264 | while (num_gh--) |
1295 | 1265 | gfs2_glock_dq_uninit(&ghs[num_gh]); | |
1296 | for (x = 0; x < num_gh; x++) | ||
1297 | gfs2_glock_dq_uninit(&ghs[x]); | ||
1298 | } | 1266 | } |
1299 | 1267 | ||
1300 | void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state) | 1268 | void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state) |
@@ -1440,42 +1408,30 @@ static struct shrinker glock_shrinker = { | |||
1440 | * @sdp: the filesystem | 1408 | * @sdp: the filesystem |
1441 | * @bucket: the bucket | 1409 | * @bucket: the bucket |
1442 | * | 1410 | * |
1443 | * Returns: 1 if the bucket has entries | ||
1444 | */ | 1411 | */ |
1445 | 1412 | ||
1446 | static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp, | 1413 | static void examine_bucket(glock_examiner examiner, const struct gfs2_sbd *sdp, |
1447 | unsigned int hash) | 1414 | unsigned int hash) |
1448 | { | 1415 | { |
1449 | struct gfs2_glock *gl, *prev = NULL; | 1416 | struct gfs2_glock *gl; |
1450 | int has_entries = 0; | 1417 | struct hlist_bl_head *head = &gl_hash_table[hash]; |
1451 | struct hlist_head *head = &gl_hash_table[hash].hb_list; | 1418 | struct hlist_bl_node *pos; |
1452 | 1419 | ||
1453 | read_lock(gl_lock_addr(hash)); | 1420 | rcu_read_lock(); |
1454 | /* Can't use hlist_for_each_entry - don't want prefetch here */ | 1421 | hlist_bl_for_each_entry_rcu(gl, pos, head, gl_list) { |
1455 | if (hlist_empty(head)) | 1422 | if ((gl->gl_sbd == sdp) && atomic_read(&gl->gl_ref)) |
1456 | goto out; | ||
1457 | gl = list_entry(head->first, struct gfs2_glock, gl_list); | ||
1458 | while(1) { | ||
1459 | if (!sdp || gl->gl_sbd == sdp) { | ||
1460 | gfs2_glock_hold(gl); | ||
1461 | read_unlock(gl_lock_addr(hash)); | ||
1462 | if (prev) | ||
1463 | gfs2_glock_put(prev); | ||
1464 | prev = gl; | ||
1465 | examiner(gl); | 1423 | examiner(gl); |
1466 | has_entries = 1; | ||
1467 | read_lock(gl_lock_addr(hash)); | ||
1468 | } | ||
1469 | if (gl->gl_list.next == NULL) | ||
1470 | break; | ||
1471 | gl = list_entry(gl->gl_list.next, struct gfs2_glock, gl_list); | ||
1472 | } | 1424 | } |
1473 | out: | 1425 | rcu_read_unlock(); |
1474 | read_unlock(gl_lock_addr(hash)); | ||
1475 | if (prev) | ||
1476 | gfs2_glock_put(prev); | ||
1477 | cond_resched(); | 1426 | cond_resched(); |
1478 | return has_entries; | 1427 | } |
1428 | |||
1429 | static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp) | ||
1430 | { | ||
1431 | unsigned x; | ||
1432 | |||
1433 | for (x = 0; x < GFS2_GL_HASH_SIZE; x++) | ||
1434 | examine_bucket(examiner, sdp, x); | ||
1479 | } | 1435 | } |
1480 | 1436 | ||
1481 | 1437 | ||
@@ -1529,10 +1485,21 @@ static void clear_glock(struct gfs2_glock *gl) | |||
1529 | 1485 | ||
1530 | void gfs2_glock_thaw(struct gfs2_sbd *sdp) | 1486 | void gfs2_glock_thaw(struct gfs2_sbd *sdp) |
1531 | { | 1487 | { |
1532 | unsigned x; | 1488 | glock_hash_walk(thaw_glock, sdp); |
1489 | } | ||
1533 | 1490 | ||
1534 | for (x = 0; x < GFS2_GL_HASH_SIZE; x++) | 1491 | static int dump_glock(struct seq_file *seq, struct gfs2_glock *gl) |
1535 | examine_bucket(thaw_glock, sdp, x); | 1492 | { |
1493 | int ret; | ||
1494 | spin_lock(&gl->gl_spin); | ||
1495 | ret = __dump_glock(seq, gl); | ||
1496 | spin_unlock(&gl->gl_spin); | ||
1497 | return ret; | ||
1498 | } | ||
1499 | |||
1500 | static void dump_glock_func(struct gfs2_glock *gl) | ||
1501 | { | ||
1502 | dump_glock(NULL, gl); | ||
1536 | } | 1503 | } |
1537 | 1504 | ||
1538 | /** | 1505 | /** |
@@ -1545,13 +1512,10 @@ void gfs2_glock_thaw(struct gfs2_sbd *sdp) | |||
1545 | 1512 | ||
1546 | void gfs2_gl_hash_clear(struct gfs2_sbd *sdp) | 1513 | void gfs2_gl_hash_clear(struct gfs2_sbd *sdp) |
1547 | { | 1514 | { |
1548 | unsigned int x; | 1515 | glock_hash_walk(clear_glock, sdp); |
1549 | |||
1550 | for (x = 0; x < GFS2_GL_HASH_SIZE; x++) | ||
1551 | examine_bucket(clear_glock, sdp, x); | ||
1552 | flush_workqueue(glock_workqueue); | 1516 | flush_workqueue(glock_workqueue); |
1553 | wait_event(sdp->sd_glock_wait, atomic_read(&sdp->sd_glock_disposal) == 0); | 1517 | wait_event(sdp->sd_glock_wait, atomic_read(&sdp->sd_glock_disposal) == 0); |
1554 | gfs2_dump_lockstate(sdp); | 1518 | glock_hash_walk(dump_glock_func, sdp); |
1555 | } | 1519 | } |
1556 | 1520 | ||
1557 | void gfs2_glock_finish_truncate(struct gfs2_inode *ip) | 1521 | void gfs2_glock_finish_truncate(struct gfs2_inode *ip) |
@@ -1717,66 +1681,15 @@ out: | |||
1717 | return error; | 1681 | return error; |
1718 | } | 1682 | } |
1719 | 1683 | ||
1720 | static int dump_glock(struct seq_file *seq, struct gfs2_glock *gl) | ||
1721 | { | ||
1722 | int ret; | ||
1723 | spin_lock(&gl->gl_spin); | ||
1724 | ret = __dump_glock(seq, gl); | ||
1725 | spin_unlock(&gl->gl_spin); | ||
1726 | return ret; | ||
1727 | } | ||
1728 | 1684 | ||
1729 | /** | ||
1730 | * gfs2_dump_lockstate - print out the current lockstate | ||
1731 | * @sdp: the filesystem | ||
1732 | * @ub: the buffer to copy the information into | ||
1733 | * | ||
1734 | * If @ub is NULL, dump the lockstate to the console. | ||
1735 | * | ||
1736 | */ | ||
1737 | |||
1738 | static int gfs2_dump_lockstate(struct gfs2_sbd *sdp) | ||
1739 | { | ||
1740 | struct gfs2_glock *gl; | ||
1741 | struct hlist_node *h; | ||
1742 | unsigned int x; | ||
1743 | int error = 0; | ||
1744 | |||
1745 | for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { | ||
1746 | |||
1747 | read_lock(gl_lock_addr(x)); | ||
1748 | |||
1749 | hlist_for_each_entry(gl, h, &gl_hash_table[x].hb_list, gl_list) { | ||
1750 | if (gl->gl_sbd != sdp) | ||
1751 | continue; | ||
1752 | |||
1753 | error = dump_glock(NULL, gl); | ||
1754 | if (error) | ||
1755 | break; | ||
1756 | } | ||
1757 | |||
1758 | read_unlock(gl_lock_addr(x)); | ||
1759 | |||
1760 | if (error) | ||
1761 | break; | ||
1762 | } | ||
1763 | |||
1764 | |||
1765 | return error; | ||
1766 | } | ||
1767 | 1685 | ||
1768 | 1686 | ||
1769 | int __init gfs2_glock_init(void) | 1687 | int __init gfs2_glock_init(void) |
1770 | { | 1688 | { |
1771 | unsigned i; | 1689 | unsigned i; |
1772 | for(i = 0; i < GFS2_GL_HASH_SIZE; i++) { | 1690 | for(i = 0; i < GFS2_GL_HASH_SIZE; i++) { |
1773 | INIT_HLIST_HEAD(&gl_hash_table[i].hb_list); | 1691 | INIT_HLIST_BL_HEAD(&gl_hash_table[i]); |
1774 | } | ||
1775 | #ifdef GL_HASH_LOCK_SZ | ||
1776 | for(i = 0; i < GL_HASH_LOCK_SZ; i++) { | ||
1777 | rwlock_init(&gl_hash_locks[i]); | ||
1778 | } | 1692 | } |
1779 | #endif | ||
1780 | 1693 | ||
1781 | glock_workqueue = alloc_workqueue("glock_workqueue", WQ_MEM_RECLAIM | | 1694 | glock_workqueue = alloc_workqueue("glock_workqueue", WQ_MEM_RECLAIM | |
1782 | WQ_HIGHPRI | WQ_FREEZABLE, 0); | 1695 | WQ_HIGHPRI | WQ_FREEZABLE, 0); |
@@ -1802,62 +1715,54 @@ void gfs2_glock_exit(void) | |||
1802 | destroy_workqueue(gfs2_delete_workqueue); | 1715 | destroy_workqueue(gfs2_delete_workqueue); |
1803 | } | 1716 | } |
1804 | 1717 | ||
1718 | static inline struct gfs2_glock *glock_hash_chain(unsigned hash) | ||
1719 | { | ||
1720 | return hlist_bl_entry(hlist_bl_first_rcu(&gl_hash_table[hash]), | ||
1721 | struct gfs2_glock, gl_list); | ||
1722 | } | ||
1723 | |||
1724 | static inline struct gfs2_glock *glock_hash_next(struct gfs2_glock *gl) | ||
1725 | { | ||
1726 | return hlist_bl_entry(rcu_dereference(gl->gl_list.next), | ||
1727 | struct gfs2_glock, gl_list); | ||
1728 | } | ||
1729 | |||
1805 | static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) | 1730 | static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) |
1806 | { | 1731 | { |
1807 | struct gfs2_glock *gl; | 1732 | struct gfs2_glock *gl; |
1808 | 1733 | ||
1809 | restart: | 1734 | do { |
1810 | read_lock(gl_lock_addr(gi->hash)); | 1735 | gl = gi->gl; |
1811 | gl = gi->gl; | 1736 | if (gl) { |
1812 | if (gl) { | 1737 | gi->gl = glock_hash_next(gl); |
1813 | gi->gl = hlist_entry(gl->gl_list.next, | 1738 | } else { |
1814 | struct gfs2_glock, gl_list); | 1739 | gi->gl = glock_hash_chain(gi->hash); |
1815 | } else { | 1740 | } |
1816 | gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first, | 1741 | while (gi->gl == NULL) { |
1817 | struct gfs2_glock, gl_list); | 1742 | gi->hash++; |
1818 | } | 1743 | if (gi->hash >= GFS2_GL_HASH_SIZE) { |
1819 | if (gi->gl) | 1744 | rcu_read_unlock(); |
1820 | gfs2_glock_hold(gi->gl); | 1745 | return 1; |
1821 | read_unlock(gl_lock_addr(gi->hash)); | 1746 | } |
1822 | if (gl) | 1747 | gi->gl = glock_hash_chain(gi->hash); |
1823 | gfs2_glock_put(gl); | 1748 | } |
1824 | while (gi->gl == NULL) { | 1749 | /* Skip entries for other sb and dead entries */ |
1825 | gi->hash++; | 1750 | } while (gi->sdp != gi->gl->gl_sbd || atomic_read(&gi->gl->gl_ref) == 0); |
1826 | if (gi->hash >= GFS2_GL_HASH_SIZE) | ||
1827 | return 1; | ||
1828 | read_lock(gl_lock_addr(gi->hash)); | ||
1829 | gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first, | ||
1830 | struct gfs2_glock, gl_list); | ||
1831 | if (gi->gl) | ||
1832 | gfs2_glock_hold(gi->gl); | ||
1833 | read_unlock(gl_lock_addr(gi->hash)); | ||
1834 | } | ||
1835 | |||
1836 | if (gi->sdp != gi->gl->gl_sbd) | ||
1837 | goto restart; | ||
1838 | 1751 | ||
1839 | return 0; | 1752 | return 0; |
1840 | } | 1753 | } |
1841 | 1754 | ||
1842 | static void gfs2_glock_iter_free(struct gfs2_glock_iter *gi) | ||
1843 | { | ||
1844 | if (gi->gl) | ||
1845 | gfs2_glock_put(gi->gl); | ||
1846 | gi->gl = NULL; | ||
1847 | } | ||
1848 | |||
1849 | static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos) | 1755 | static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos) |
1850 | { | 1756 | { |
1851 | struct gfs2_glock_iter *gi = seq->private; | 1757 | struct gfs2_glock_iter *gi = seq->private; |
1852 | loff_t n = *pos; | 1758 | loff_t n = *pos; |
1853 | 1759 | ||
1854 | gi->hash = 0; | 1760 | gi->hash = 0; |
1761 | rcu_read_lock(); | ||
1855 | 1762 | ||
1856 | do { | 1763 | do { |
1857 | if (gfs2_glock_iter_next(gi)) { | 1764 | if (gfs2_glock_iter_next(gi)) |
1858 | gfs2_glock_iter_free(gi); | ||
1859 | return NULL; | 1765 | return NULL; |
1860 | } | ||
1861 | } while (n--); | 1766 | } while (n--); |
1862 | 1767 | ||
1863 | return gi->gl; | 1768 | return gi->gl; |
@@ -1870,10 +1775,8 @@ static void *gfs2_glock_seq_next(struct seq_file *seq, void *iter_ptr, | |||
1870 | 1775 | ||
1871 | (*pos)++; | 1776 | (*pos)++; |
1872 | 1777 | ||
1873 | if (gfs2_glock_iter_next(gi)) { | 1778 | if (gfs2_glock_iter_next(gi)) |
1874 | gfs2_glock_iter_free(gi); | ||
1875 | return NULL; | 1779 | return NULL; |
1876 | } | ||
1877 | 1780 | ||
1878 | return gi->gl; | 1781 | return gi->gl; |
1879 | } | 1782 | } |
@@ -1881,7 +1784,10 @@ static void *gfs2_glock_seq_next(struct seq_file *seq, void *iter_ptr, | |||
1881 | static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr) | 1784 | static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr) |
1882 | { | 1785 | { |
1883 | struct gfs2_glock_iter *gi = seq->private; | 1786 | struct gfs2_glock_iter *gi = seq->private; |
1884 | gfs2_glock_iter_free(gi); | 1787 | |
1788 | if (gi->gl) | ||
1789 | rcu_read_unlock(); | ||
1790 | gi->gl = NULL; | ||
1885 | } | 1791 | } |
1886 | 1792 | ||
1887 | static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr) | 1793 | static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr) |
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 691851ceb61..aea160690e9 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h | |||
@@ -118,7 +118,7 @@ struct lm_lockops { | |||
118 | int (*lm_mount) (struct gfs2_sbd *sdp, const char *fsname); | 118 | int (*lm_mount) (struct gfs2_sbd *sdp, const char *fsname); |
119 | void (*lm_unmount) (struct gfs2_sbd *sdp); | 119 | void (*lm_unmount) (struct gfs2_sbd *sdp); |
120 | void (*lm_withdraw) (struct gfs2_sbd *sdp); | 120 | void (*lm_withdraw) (struct gfs2_sbd *sdp); |
121 | void (*lm_put_lock) (struct kmem_cache *cachep, struct gfs2_glock *gl); | 121 | void (*lm_put_lock) (struct gfs2_glock *gl); |
122 | int (*lm_lock) (struct gfs2_glock *gl, unsigned int req_state, | 122 | int (*lm_lock) (struct gfs2_glock *gl, unsigned int req_state, |
123 | unsigned int flags); | 123 | unsigned int flags); |
124 | void (*lm_cancel) (struct gfs2_glock *gl); | 124 | void (*lm_cancel) (struct gfs2_glock *gl); |
@@ -174,7 +174,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, | |||
174 | int create, struct gfs2_glock **glp); | 174 | int create, struct gfs2_glock **glp); |
175 | void gfs2_glock_hold(struct gfs2_glock *gl); | 175 | void gfs2_glock_hold(struct gfs2_glock *gl); |
176 | void gfs2_glock_put_nolock(struct gfs2_glock *gl); | 176 | void gfs2_glock_put_nolock(struct gfs2_glock *gl); |
177 | int gfs2_glock_put(struct gfs2_glock *gl); | 177 | void gfs2_glock_put(struct gfs2_glock *gl); |
178 | void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, | 178 | void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, |
179 | struct gfs2_holder *gh); | 179 | struct gfs2_holder *gh); |
180 | void gfs2_holder_reinit(unsigned int state, unsigned flags, | 180 | void gfs2_holder_reinit(unsigned int state, unsigned flags, |
@@ -223,25 +223,22 @@ static inline int gfs2_glock_nq_init(struct gfs2_glock *gl, | |||
223 | return error; | 223 | return error; |
224 | } | 224 | } |
225 | 225 | ||
226 | /* Lock Value Block functions */ | 226 | extern void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state); |
227 | 227 | extern void gfs2_glock_complete(struct gfs2_glock *gl, int ret); | |
228 | int gfs2_lvb_hold(struct gfs2_glock *gl); | 228 | extern void gfs2_reclaim_glock(struct gfs2_sbd *sdp); |
229 | void gfs2_lvb_unhold(struct gfs2_glock *gl); | 229 | extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); |
230 | 230 | extern void gfs2_glock_finish_truncate(struct gfs2_inode *ip); | |
231 | void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state); | 231 | extern void gfs2_glock_thaw(struct gfs2_sbd *sdp); |
232 | void gfs2_glock_complete(struct gfs2_glock *gl, int ret); | 232 | extern void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl); |
233 | void gfs2_reclaim_glock(struct gfs2_sbd *sdp); | 233 | extern void gfs2_glock_free(struct gfs2_glock *gl); |
234 | void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); | 234 | |
235 | void gfs2_glock_finish_truncate(struct gfs2_inode *ip); | 235 | extern int __init gfs2_glock_init(void); |
236 | void gfs2_glock_thaw(struct gfs2_sbd *sdp); | 236 | extern void gfs2_glock_exit(void); |
237 | 237 | ||
238 | int __init gfs2_glock_init(void); | 238 | extern int gfs2_create_debugfs_file(struct gfs2_sbd *sdp); |
239 | void gfs2_glock_exit(void); | 239 | extern void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp); |
240 | 240 | extern int gfs2_register_debugfs(void); | |
241 | int gfs2_create_debugfs_file(struct gfs2_sbd *sdp); | 241 | extern void gfs2_unregister_debugfs(void); |
242 | void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp); | ||
243 | int gfs2_register_debugfs(void); | ||
244 | void gfs2_unregister_debugfs(void); | ||
245 | 242 | ||
246 | extern const struct lm_lockops gfs2_dlm_ops; | 243 | extern const struct lm_lockops gfs2_dlm_ops; |
247 | 244 | ||
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 263561bf1a5..3754e3cbf02 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
@@ -56,20 +56,26 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) | |||
56 | BUG_ON(current->journal_info); | 56 | BUG_ON(current->journal_info); |
57 | current->journal_info = &tr; | 57 | current->journal_info = &tr; |
58 | 58 | ||
59 | gfs2_log_lock(sdp); | 59 | spin_lock(&sdp->sd_ail_lock); |
60 | while (!list_empty(head)) { | 60 | while (!list_empty(head)) { |
61 | bd = list_entry(head->next, struct gfs2_bufdata, | 61 | bd = list_entry(head->next, struct gfs2_bufdata, |
62 | bd_ail_gl_list); | 62 | bd_ail_gl_list); |
63 | bh = bd->bd_bh; | 63 | bh = bd->bd_bh; |
64 | gfs2_remove_from_ail(bd); | 64 | gfs2_remove_from_ail(bd); |
65 | spin_unlock(&sdp->sd_ail_lock); | ||
66 | |||
65 | bd->bd_bh = NULL; | 67 | bd->bd_bh = NULL; |
66 | bh->b_private = NULL; | 68 | bh->b_private = NULL; |
67 | bd->bd_blkno = bh->b_blocknr; | 69 | bd->bd_blkno = bh->b_blocknr; |
70 | gfs2_log_lock(sdp); | ||
68 | gfs2_assert_withdraw(sdp, !buffer_busy(bh)); | 71 | gfs2_assert_withdraw(sdp, !buffer_busy(bh)); |
69 | gfs2_trans_add_revoke(sdp, bd); | 72 | gfs2_trans_add_revoke(sdp, bd); |
73 | gfs2_log_unlock(sdp); | ||
74 | |||
75 | spin_lock(&sdp->sd_ail_lock); | ||
70 | } | 76 | } |
71 | gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); | 77 | gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); |
72 | gfs2_log_unlock(sdp); | 78 | spin_unlock(&sdp->sd_ail_lock); |
73 | 79 | ||
74 | gfs2_trans_end(sdp); | 80 | gfs2_trans_end(sdp); |
75 | gfs2_log_flush(sdp, NULL); | 81 | gfs2_log_flush(sdp, NULL); |
@@ -206,8 +212,17 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) | |||
206 | static int inode_go_demote_ok(const struct gfs2_glock *gl) | 212 | static int inode_go_demote_ok(const struct gfs2_glock *gl) |
207 | { | 213 | { |
208 | struct gfs2_sbd *sdp = gl->gl_sbd; | 214 | struct gfs2_sbd *sdp = gl->gl_sbd; |
215 | struct gfs2_holder *gh; | ||
216 | |||
209 | if (sdp->sd_jindex == gl->gl_object || sdp->sd_rindex == gl->gl_object) | 217 | if (sdp->sd_jindex == gl->gl_object || sdp->sd_rindex == gl->gl_object) |
210 | return 0; | 218 | return 0; |
219 | |||
220 | if (!list_empty(&gl->gl_holders)) { | ||
221 | gh = list_entry(gl->gl_holders.next, struct gfs2_holder, gh_list); | ||
222 | if (gh->gh_list.next != &gl->gl_holders) | ||
223 | return 0; | ||
224 | } | ||
225 | |||
211 | return 1; | 226 | return 1; |
212 | } | 227 | } |
213 | 228 | ||
@@ -272,19 +287,6 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl) | |||
272 | } | 287 | } |
273 | 288 | ||
274 | /** | 289 | /** |
275 | * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock | ||
276 | * @gl: the glock | ||
277 | * | ||
278 | * Returns: 1 if it's ok | ||
279 | */ | ||
280 | |||
281 | static int rgrp_go_demote_ok(const struct gfs2_glock *gl) | ||
282 | { | ||
283 | const struct address_space *mapping = (const struct address_space *)(gl + 1); | ||
284 | return !mapping->nrpages; | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * rgrp_go_lock - operation done after an rgrp lock is locked by | 290 | * rgrp_go_lock - operation done after an rgrp lock is locked by |
289 | * a first holder on this node. | 291 | * a first holder on this node. |
290 | * @gl: the glock | 292 | * @gl: the glock |
@@ -410,7 +412,6 @@ const struct gfs2_glock_operations gfs2_inode_glops = { | |||
410 | const struct gfs2_glock_operations gfs2_rgrp_glops = { | 412 | const struct gfs2_glock_operations gfs2_rgrp_glops = { |
411 | .go_xmote_th = rgrp_go_sync, | 413 | .go_xmote_th = rgrp_go_sync, |
412 | .go_inval = rgrp_go_inval, | 414 | .go_inval = rgrp_go_inval, |
413 | .go_demote_ok = rgrp_go_demote_ok, | ||
414 | .go_lock = rgrp_go_lock, | 415 | .go_lock = rgrp_go_lock, |
415 | .go_unlock = rgrp_go_unlock, | 416 | .go_unlock = rgrp_go_unlock, |
416 | .go_dump = gfs2_rgrp_dump, | 417 | .go_dump = gfs2_rgrp_dump, |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index a79790c0627..870a89d6d4d 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -15,6 +15,8 @@ | |||
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/dlm.h> | 16 | #include <linux/dlm.h> |
17 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
18 | #include <linux/rcupdate.h> | ||
19 | #include <linux/rculist_bl.h> | ||
18 | 20 | ||
19 | #define DIO_WAIT 0x00000010 | 21 | #define DIO_WAIT 0x00000010 |
20 | #define DIO_METADATA 0x00000020 | 22 | #define DIO_METADATA 0x00000020 |
@@ -201,7 +203,7 @@ enum { | |||
201 | }; | 203 | }; |
202 | 204 | ||
203 | struct gfs2_glock { | 205 | struct gfs2_glock { |
204 | struct hlist_node gl_list; | 206 | struct hlist_bl_node gl_list; |
205 | unsigned long gl_flags; /* GLF_... */ | 207 | unsigned long gl_flags; /* GLF_... */ |
206 | struct lm_lockname gl_name; | 208 | struct lm_lockname gl_name; |
207 | atomic_t gl_ref; | 209 | atomic_t gl_ref; |
@@ -234,6 +236,7 @@ struct gfs2_glock { | |||
234 | atomic_t gl_ail_count; | 236 | atomic_t gl_ail_count; |
235 | struct delayed_work gl_work; | 237 | struct delayed_work gl_work; |
236 | struct work_struct gl_delete; | 238 | struct work_struct gl_delete; |
239 | struct rcu_head gl_rcu; | ||
237 | }; | 240 | }; |
238 | 241 | ||
239 | #define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */ | 242 | #define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */ |
@@ -314,6 +317,7 @@ enum { | |||
314 | QDF_USER = 0, | 317 | QDF_USER = 0, |
315 | QDF_CHANGE = 1, | 318 | QDF_CHANGE = 1, |
316 | QDF_LOCKED = 2, | 319 | QDF_LOCKED = 2, |
320 | QDF_REFRESH = 3, | ||
317 | }; | 321 | }; |
318 | 322 | ||
319 | struct gfs2_quota_data { | 323 | struct gfs2_quota_data { |
@@ -647,6 +651,7 @@ struct gfs2_sbd { | |||
647 | unsigned int sd_log_flush_head; | 651 | unsigned int sd_log_flush_head; |
648 | u64 sd_log_flush_wrapped; | 652 | u64 sd_log_flush_wrapped; |
649 | 653 | ||
654 | spinlock_t sd_ail_lock; | ||
650 | struct list_head sd_ail1_list; | 655 | struct list_head sd_ail1_list; |
651 | struct list_head sd_ail2_list; | 656 | struct list_head sd_ail2_list; |
652 | u64 sd_ail_sync_gen; | 657 | u64 sd_ail_sync_gen; |
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index 6e493aee28f..98c80d8c2a6 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c | |||
@@ -22,7 +22,6 @@ static void gdlm_ast(void *arg) | |||
22 | { | 22 | { |
23 | struct gfs2_glock *gl = arg; | 23 | struct gfs2_glock *gl = arg; |
24 | unsigned ret = gl->gl_state; | 24 | unsigned ret = gl->gl_state; |
25 | struct gfs2_sbd *sdp = gl->gl_sbd; | ||
26 | 25 | ||
27 | BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED); | 26 | BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED); |
28 | 27 | ||
@@ -31,12 +30,7 @@ static void gdlm_ast(void *arg) | |||
31 | 30 | ||
32 | switch (gl->gl_lksb.sb_status) { | 31 | switch (gl->gl_lksb.sb_status) { |
33 | case -DLM_EUNLOCK: /* Unlocked, so glock can be freed */ | 32 | case -DLM_EUNLOCK: /* Unlocked, so glock can be freed */ |
34 | if (gl->gl_ops->go_flags & GLOF_ASPACE) | 33 | gfs2_glock_free(gl); |
35 | kmem_cache_free(gfs2_glock_aspace_cachep, gl); | ||
36 | else | ||
37 | kmem_cache_free(gfs2_glock_cachep, gl); | ||
38 | if (atomic_dec_and_test(&sdp->sd_glock_disposal)) | ||
39 | wake_up(&sdp->sd_glock_wait); | ||
40 | return; | 34 | return; |
41 | case -DLM_ECANCEL: /* Cancel while getting lock */ | 35 | case -DLM_ECANCEL: /* Cancel while getting lock */ |
42 | ret |= LM_OUT_CANCELED; | 36 | ret |= LM_OUT_CANCELED; |
@@ -164,16 +158,14 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, | |||
164 | GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); | 158 | GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); |
165 | } | 159 | } |
166 | 160 | ||
167 | static void gdlm_put_lock(struct kmem_cache *cachep, struct gfs2_glock *gl) | 161 | static void gdlm_put_lock(struct gfs2_glock *gl) |
168 | { | 162 | { |
169 | struct gfs2_sbd *sdp = gl->gl_sbd; | 163 | struct gfs2_sbd *sdp = gl->gl_sbd; |
170 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; | 164 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; |
171 | int error; | 165 | int error; |
172 | 166 | ||
173 | if (gl->gl_lksb.sb_lkid == 0) { | 167 | if (gl->gl_lksb.sb_lkid == 0) { |
174 | kmem_cache_free(cachep, gl); | 168 | gfs2_glock_free(gl); |
175 | if (atomic_dec_and_test(&sdp->sd_glock_disposal)) | ||
176 | wake_up(&sdp->sd_glock_wait); | ||
177 | return; | 169 | return; |
178 | } | 170 | } |
179 | 171 | ||
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index eb01f3575e1..e7ed31f858d 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -67,7 +67,7 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, | |||
67 | * @mapping: The associated mapping (maybe NULL) | 67 | * @mapping: The associated mapping (maybe NULL) |
68 | * @bd: The gfs2_bufdata to remove | 68 | * @bd: The gfs2_bufdata to remove |
69 | * | 69 | * |
70 | * The log lock _must_ be held when calling this function | 70 | * The ail lock _must_ be held when calling this function |
71 | * | 71 | * |
72 | */ | 72 | */ |
73 | 73 | ||
@@ -88,8 +88,8 @@ void gfs2_remove_from_ail(struct gfs2_bufdata *bd) | |||
88 | */ | 88 | */ |
89 | 89 | ||
90 | static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | 90 | static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) |
91 | __releases(&sdp->sd_log_lock) | 91 | __releases(&sdp->sd_ail_lock) |
92 | __acquires(&sdp->sd_log_lock) | 92 | __acquires(&sdp->sd_ail_lock) |
93 | { | 93 | { |
94 | struct gfs2_bufdata *bd, *s; | 94 | struct gfs2_bufdata *bd, *s; |
95 | struct buffer_head *bh; | 95 | struct buffer_head *bh; |
@@ -117,7 +117,7 @@ __acquires(&sdp->sd_log_lock) | |||
117 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); | 117 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); |
118 | 118 | ||
119 | get_bh(bh); | 119 | get_bh(bh); |
120 | gfs2_log_unlock(sdp); | 120 | spin_unlock(&sdp->sd_ail_lock); |
121 | lock_buffer(bh); | 121 | lock_buffer(bh); |
122 | if (test_clear_buffer_dirty(bh)) { | 122 | if (test_clear_buffer_dirty(bh)) { |
123 | bh->b_end_io = end_buffer_write_sync; | 123 | bh->b_end_io = end_buffer_write_sync; |
@@ -126,7 +126,7 @@ __acquires(&sdp->sd_log_lock) | |||
126 | unlock_buffer(bh); | 126 | unlock_buffer(bh); |
127 | brelse(bh); | 127 | brelse(bh); |
128 | } | 128 | } |
129 | gfs2_log_lock(sdp); | 129 | spin_lock(&sdp->sd_ail_lock); |
130 | 130 | ||
131 | retry = 1; | 131 | retry = 1; |
132 | break; | 132 | break; |
@@ -175,10 +175,10 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp) | |||
175 | struct gfs2_ail *ai; | 175 | struct gfs2_ail *ai; |
176 | int done = 0; | 176 | int done = 0; |
177 | 177 | ||
178 | gfs2_log_lock(sdp); | 178 | spin_lock(&sdp->sd_ail_lock); |
179 | head = &sdp->sd_ail1_list; | 179 | head = &sdp->sd_ail1_list; |
180 | if (list_empty(head)) { | 180 | if (list_empty(head)) { |
181 | gfs2_log_unlock(sdp); | 181 | spin_unlock(&sdp->sd_ail_lock); |
182 | return; | 182 | return; |
183 | } | 183 | } |
184 | sync_gen = sdp->sd_ail_sync_gen++; | 184 | sync_gen = sdp->sd_ail_sync_gen++; |
@@ -189,13 +189,13 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp) | |||
189 | if (ai->ai_sync_gen >= sync_gen) | 189 | if (ai->ai_sync_gen >= sync_gen) |
190 | continue; | 190 | continue; |
191 | ai->ai_sync_gen = sync_gen; | 191 | ai->ai_sync_gen = sync_gen; |
192 | gfs2_ail1_start_one(sdp, ai); /* This may drop log lock */ | 192 | gfs2_ail1_start_one(sdp, ai); /* This may drop ail lock */ |
193 | done = 0; | 193 | done = 0; |
194 | break; | 194 | break; |
195 | } | 195 | } |
196 | } | 196 | } |
197 | 197 | ||
198 | gfs2_log_unlock(sdp); | 198 | spin_unlock(&sdp->sd_ail_lock); |
199 | } | 199 | } |
200 | 200 | ||
201 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) | 201 | static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) |
@@ -203,7 +203,7 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) | |||
203 | struct gfs2_ail *ai, *s; | 203 | struct gfs2_ail *ai, *s; |
204 | int ret; | 204 | int ret; |
205 | 205 | ||
206 | gfs2_log_lock(sdp); | 206 | spin_lock(&sdp->sd_ail_lock); |
207 | 207 | ||
208 | list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { | 208 | list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { |
209 | if (gfs2_ail1_empty_one(sdp, ai, flags)) | 209 | if (gfs2_ail1_empty_one(sdp, ai, flags)) |
@@ -214,7 +214,7 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) | |||
214 | 214 | ||
215 | ret = list_empty(&sdp->sd_ail1_list); | 215 | ret = list_empty(&sdp->sd_ail1_list); |
216 | 216 | ||
217 | gfs2_log_unlock(sdp); | 217 | spin_unlock(&sdp->sd_ail_lock); |
218 | 218 | ||
219 | return ret; | 219 | return ret; |
220 | } | 220 | } |
@@ -247,7 +247,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) | |||
247 | int wrap = (new_tail < old_tail); | 247 | int wrap = (new_tail < old_tail); |
248 | int a, b, rm; | 248 | int a, b, rm; |
249 | 249 | ||
250 | gfs2_log_lock(sdp); | 250 | spin_lock(&sdp->sd_ail_lock); |
251 | 251 | ||
252 | list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) { | 252 | list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) { |
253 | a = (old_tail <= ai->ai_first); | 253 | a = (old_tail <= ai->ai_first); |
@@ -263,7 +263,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) | |||
263 | kfree(ai); | 263 | kfree(ai); |
264 | } | 264 | } |
265 | 265 | ||
266 | gfs2_log_unlock(sdp); | 266 | spin_unlock(&sdp->sd_ail_lock); |
267 | } | 267 | } |
268 | 268 | ||
269 | /** | 269 | /** |
@@ -421,7 +421,7 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) | |||
421 | struct gfs2_ail *ai; | 421 | struct gfs2_ail *ai; |
422 | unsigned int tail; | 422 | unsigned int tail; |
423 | 423 | ||
424 | gfs2_log_lock(sdp); | 424 | spin_lock(&sdp->sd_ail_lock); |
425 | 425 | ||
426 | if (list_empty(&sdp->sd_ail1_list)) { | 426 | if (list_empty(&sdp->sd_ail1_list)) { |
427 | tail = sdp->sd_log_head; | 427 | tail = sdp->sd_log_head; |
@@ -430,7 +430,7 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) | |||
430 | tail = ai->ai_first; | 430 | tail = ai->ai_first; |
431 | } | 431 | } |
432 | 432 | ||
433 | gfs2_log_unlock(sdp); | 433 | spin_unlock(&sdp->sd_ail_lock); |
434 | 434 | ||
435 | return tail; | 435 | return tail; |
436 | } | 436 | } |
@@ -743,10 +743,12 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
743 | sdp->sd_log_commited_databuf = 0; | 743 | sdp->sd_log_commited_databuf = 0; |
744 | sdp->sd_log_commited_revoke = 0; | 744 | sdp->sd_log_commited_revoke = 0; |
745 | 745 | ||
746 | spin_lock(&sdp->sd_ail_lock); | ||
746 | if (!list_empty(&ai->ai_ail1_list)) { | 747 | if (!list_empty(&ai->ai_ail1_list)) { |
747 | list_add(&ai->ai_list, &sdp->sd_ail1_list); | 748 | list_add(&ai->ai_list, &sdp->sd_ail1_list); |
748 | ai = NULL; | 749 | ai = NULL; |
749 | } | 750 | } |
751 | spin_unlock(&sdp->sd_ail_lock); | ||
750 | gfs2_log_unlock(sdp); | 752 | gfs2_log_unlock(sdp); |
751 | trace_gfs2_log_flush(sdp, 0); | 753 | trace_gfs2_log_flush(sdp, 0); |
752 | up_write(&sdp->sd_log_flush_lock); | 754 | up_write(&sdp->sd_log_flush_lock); |
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index bf33f822058..e919abf25ec 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c | |||
@@ -51,8 +51,10 @@ static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) | |||
51 | /* If this buffer is in the AIL and it has already been written | 51 | /* If this buffer is in the AIL and it has already been written |
52 | * to in-place disk block, remove it from the AIL. | 52 | * to in-place disk block, remove it from the AIL. |
53 | */ | 53 | */ |
54 | spin_lock(&sdp->sd_ail_lock); | ||
54 | if (bd->bd_ail) | 55 | if (bd->bd_ail) |
55 | list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); | 56 | list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); |
57 | spin_unlock(&sdp->sd_ail_lock); | ||
56 | get_bh(bh); | 58 | get_bh(bh); |
57 | atomic_inc(&sdp->sd_log_pinned); | 59 | atomic_inc(&sdp->sd_log_pinned); |
58 | trace_gfs2_pin(bd, 1); | 60 | trace_gfs2_pin(bd, 1); |
@@ -80,7 +82,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, | |||
80 | mark_buffer_dirty(bh); | 82 | mark_buffer_dirty(bh); |
81 | clear_buffer_pinned(bh); | 83 | clear_buffer_pinned(bh); |
82 | 84 | ||
83 | gfs2_log_lock(sdp); | 85 | spin_lock(&sdp->sd_ail_lock); |
84 | if (bd->bd_ail) { | 86 | if (bd->bd_ail) { |
85 | list_del(&bd->bd_ail_st_list); | 87 | list_del(&bd->bd_ail_st_list); |
86 | brelse(bh); | 88 | brelse(bh); |
@@ -91,9 +93,11 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, | |||
91 | } | 93 | } |
92 | bd->bd_ail = ai; | 94 | bd->bd_ail = ai; |
93 | list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); | 95 | list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); |
94 | clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); | 96 | spin_unlock(&sdp->sd_ail_lock); |
97 | |||
98 | if (test_and_clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags)) | ||
99 | gfs2_glock_schedule_for_reclaim(bd->bd_gl); | ||
95 | trace_gfs2_pin(bd, 0); | 100 | trace_gfs2_pin(bd, 0); |
96 | gfs2_log_unlock(sdp); | ||
97 | unlock_buffer(bh); | 101 | unlock_buffer(bh); |
98 | atomic_dec(&sdp->sd_log_pinned); | 102 | atomic_dec(&sdp->sd_log_pinned); |
99 | } | 103 | } |
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 72c31a315d9..888a5f5a1a5 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/gfs2_ondisk.h> | 16 | #include <linux/gfs2_ondisk.h> |
17 | #include <linux/rcupdate.h> | ||
18 | #include <linux/rculist_bl.h> | ||
17 | #include <asm/atomic.h> | 19 | #include <asm/atomic.h> |
18 | 20 | ||
19 | #include "gfs2.h" | 21 | #include "gfs2.h" |
@@ -45,7 +47,7 @@ static void gfs2_init_glock_once(void *foo) | |||
45 | { | 47 | { |
46 | struct gfs2_glock *gl = foo; | 48 | struct gfs2_glock *gl = foo; |
47 | 49 | ||
48 | INIT_HLIST_NODE(&gl->gl_list); | 50 | INIT_HLIST_BL_NODE(&gl->gl_list); |
49 | spin_lock_init(&gl->gl_spin); | 51 | spin_lock_init(&gl->gl_spin); |
50 | INIT_LIST_HEAD(&gl->gl_holders); | 52 | INIT_LIST_HEAD(&gl->gl_holders); |
51 | INIT_LIST_HEAD(&gl->gl_lru); | 53 | INIT_LIST_HEAD(&gl->gl_lru); |
@@ -191,6 +193,8 @@ static void __exit exit_gfs2_fs(void) | |||
191 | unregister_filesystem(&gfs2meta_fs_type); | 193 | unregister_filesystem(&gfs2meta_fs_type); |
192 | destroy_workqueue(gfs_recovery_wq); | 194 | destroy_workqueue(gfs_recovery_wq); |
193 | 195 | ||
196 | rcu_barrier(); | ||
197 | |||
194 | kmem_cache_destroy(gfs2_quotad_cachep); | 198 | kmem_cache_destroy(gfs2_quotad_cachep); |
195 | kmem_cache_destroy(gfs2_rgrpd_cachep); | 199 | kmem_cache_destroy(gfs2_rgrpd_cachep); |
196 | kmem_cache_destroy(gfs2_bufdata_cachep); | 200 | kmem_cache_destroy(gfs2_bufdata_cachep); |
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 939739c7b3f..01d97f48655 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c | |||
@@ -326,6 +326,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int | |||
326 | brelse(bh); | 326 | brelse(bh); |
327 | } | 327 | } |
328 | if (bd) { | 328 | if (bd) { |
329 | spin_lock(&sdp->sd_ail_lock); | ||
329 | if (bd->bd_ail) { | 330 | if (bd->bd_ail) { |
330 | gfs2_remove_from_ail(bd); | 331 | gfs2_remove_from_ail(bd); |
331 | bh->b_private = NULL; | 332 | bh->b_private = NULL; |
@@ -333,6 +334,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int | |||
333 | bd->bd_blkno = bh->b_blocknr; | 334 | bd->bd_blkno = bh->b_blocknr; |
334 | gfs2_trans_add_revoke(sdp, bd); | 335 | gfs2_trans_add_revoke(sdp, bd); |
335 | } | 336 | } |
337 | spin_unlock(&sdp->sd_ail_lock); | ||
336 | } | 338 | } |
337 | clear_buffer_dirty(bh); | 339 | clear_buffer_dirty(bh); |
338 | clear_buffer_uptodate(bh); | 340 | clear_buffer_uptodate(bh); |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 777927ce6f7..42ef24355af 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -99,6 +99,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) | |||
99 | 99 | ||
100 | init_waitqueue_head(&sdp->sd_log_waitq); | 100 | init_waitqueue_head(&sdp->sd_log_waitq); |
101 | init_waitqueue_head(&sdp->sd_logd_waitq); | 101 | init_waitqueue_head(&sdp->sd_logd_waitq); |
102 | spin_lock_init(&sdp->sd_ail_lock); | ||
102 | INIT_LIST_HEAD(&sdp->sd_ail1_list); | 103 | INIT_LIST_HEAD(&sdp->sd_ail1_list); |
103 | INIT_LIST_HEAD(&sdp->sd_ail2_list); | 104 | INIT_LIST_HEAD(&sdp->sd_ail2_list); |
104 | 105 | ||
@@ -928,17 +929,9 @@ static const match_table_t nolock_tokens = { | |||
928 | { Opt_err, NULL }, | 929 | { Opt_err, NULL }, |
929 | }; | 930 | }; |
930 | 931 | ||
931 | static void nolock_put_lock(struct kmem_cache *cachep, struct gfs2_glock *gl) | ||
932 | { | ||
933 | struct gfs2_sbd *sdp = gl->gl_sbd; | ||
934 | kmem_cache_free(cachep, gl); | ||
935 | if (atomic_dec_and_test(&sdp->sd_glock_disposal)) | ||
936 | wake_up(&sdp->sd_glock_wait); | ||
937 | } | ||
938 | |||
939 | static const struct lm_lockops nolock_ops = { | 932 | static const struct lm_lockops nolock_ops = { |
940 | .lm_proto_name = "lock_nolock", | 933 | .lm_proto_name = "lock_nolock", |
941 | .lm_put_lock = nolock_put_lock, | 934 | .lm_put_lock = gfs2_glock_free, |
942 | .lm_tokens = &nolock_tokens, | 935 | .lm_tokens = &nolock_tokens, |
943 | }; | 936 | }; |
944 | 937 | ||
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index d8b26ac2e20..09e436a5072 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -1026,9 +1026,9 @@ static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) | |||
1026 | 1026 | ||
1027 | /** | 1027 | /** |
1028 | * gfs2_permission - | 1028 | * gfs2_permission - |
1029 | * @inode: | 1029 | * @inode: The inode |
1030 | * @mask: | 1030 | * @mask: The mask to be tested |
1031 | * @nd: passed from Linux VFS, ignored by us | 1031 | * @flags: Indicates whether this is an RCU path walk or not |
1032 | * | 1032 | * |
1033 | * This may be called from the VFS directly, or from within GFS2 with the | 1033 | * This may be called from the VFS directly, or from within GFS2 with the |
1034 | * inode locked, so we look to see if the glock is already locked and only | 1034 | * inode locked, so we look to see if the glock is already locked and only |
@@ -1044,11 +1044,11 @@ int gfs2_permission(struct inode *inode, int mask, unsigned int flags) | |||
1044 | int error; | 1044 | int error; |
1045 | int unlock = 0; | 1045 | int unlock = 0; |
1046 | 1046 | ||
1047 | if (flags & IPERM_FLAG_RCU) | ||
1048 | return -ECHILD; | ||
1049 | 1047 | ||
1050 | ip = GFS2_I(inode); | 1048 | ip = GFS2_I(inode); |
1051 | if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { | 1049 | if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { |
1050 | if (flags & IPERM_FLAG_RCU) | ||
1051 | return -ECHILD; | ||
1052 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | 1052 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
1053 | if (error) | 1053 | if (error) |
1054 | return error; | 1054 | return error; |
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index a689901963d..e23d9864c41 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
@@ -834,6 +834,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) | |||
834 | goto out_end_trans; | 834 | goto out_end_trans; |
835 | 835 | ||
836 | do_qc(qd, -qd->qd_change_sync); | 836 | do_qc(qd, -qd->qd_change_sync); |
837 | set_bit(QDF_REFRESH, &qd->qd_flags); | ||
837 | } | 838 | } |
838 | 839 | ||
839 | error = 0; | 840 | error = 0; |
@@ -929,6 +930,7 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid) | |||
929 | { | 930 | { |
930 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 931 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
931 | struct gfs2_alloc *al = ip->i_alloc; | 932 | struct gfs2_alloc *al = ip->i_alloc; |
933 | struct gfs2_quota_data *qd; | ||
932 | unsigned int x; | 934 | unsigned int x; |
933 | int error = 0; | 935 | int error = 0; |
934 | 936 | ||
@@ -942,7 +944,11 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid) | |||
942 | sort_qd, NULL); | 944 | sort_qd, NULL); |
943 | 945 | ||
944 | for (x = 0; x < al->al_qd_num; x++) { | 946 | for (x = 0; x < al->al_qd_num; x++) { |
945 | error = do_glock(al->al_qd[x], NO_FORCE, &al->al_qd_ghs[x]); | 947 | int force = NO_FORCE; |
948 | qd = al->al_qd[x]; | ||
949 | if (test_and_clear_bit(QDF_REFRESH, &qd->qd_flags)) | ||
950 | force = FORCE; | ||
951 | error = do_glock(qd, force, &al->al_qd_ghs[x]); | ||
946 | if (error) | 952 | if (error) |
947 | break; | 953 | break; |
948 | } | 954 | } |
@@ -1587,6 +1593,8 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id, | |||
1587 | 1593 | ||
1588 | offset = qd2offset(qd); | 1594 | offset = qd2offset(qd); |
1589 | alloc_required = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota)); | 1595 | alloc_required = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota)); |
1596 | if (gfs2_is_stuffed(ip)) | ||
1597 | alloc_required = 1; | ||
1590 | if (alloc_required) { | 1598 | if (alloc_required) { |
1591 | al = gfs2_alloc_get(ip); | 1599 | al = gfs2_alloc_get(ip); |
1592 | if (al == NULL) | 1600 | if (al == NULL) |
@@ -1600,7 +1608,9 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id, | |||
1600 | blocks += gfs2_rg_blocks(al); | 1608 | blocks += gfs2_rg_blocks(al); |
1601 | } | 1609 | } |
1602 | 1610 | ||
1603 | error = gfs2_trans_begin(sdp, blocks + RES_DINODE + 1, 0); | 1611 | /* Some quotas span block boundaries and can update two blocks, |
1612 | adding an extra block to the transaction to handle such quotas */ | ||
1613 | error = gfs2_trans_begin(sdp, blocks + RES_DINODE + 2, 0); | ||
1604 | if (error) | 1614 | if (error) |
1605 | goto out_release; | 1615 | goto out_release; |
1606 | 1616 | ||
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 7293ea27020..cf930cd9664 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -1602,7 +1602,7 @@ rgrp_error: | |||
1602 | * | 1602 | * |
1603 | */ | 1603 | */ |
1604 | 1604 | ||
1605 | void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) | 1605 | void __gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) |
1606 | { | 1606 | { |
1607 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1607 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1608 | struct gfs2_rgrpd *rgd; | 1608 | struct gfs2_rgrpd *rgd; |
@@ -1617,7 +1617,21 @@ void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) | |||
1617 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); | 1617 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); |
1618 | 1618 | ||
1619 | gfs2_trans_add_rg(rgd); | 1619 | gfs2_trans_add_rg(rgd); |
1620 | } | ||
1620 | 1621 | ||
1622 | /** | ||
1623 | * gfs2_free_data - free a contiguous run of data block(s) | ||
1624 | * @ip: the inode these blocks are being freed from | ||
1625 | * @bstart: first block of a run of contiguous blocks | ||
1626 | * @blen: the length of the block run | ||
1627 | * | ||
1628 | */ | ||
1629 | |||
1630 | void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) | ||
1631 | { | ||
1632 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
1633 | |||
1634 | __gfs2_free_data(ip, bstart, blen); | ||
1621 | gfs2_statfs_change(sdp, 0, +blen, 0); | 1635 | gfs2_statfs_change(sdp, 0, +blen, 0); |
1622 | gfs2_quota_change(ip, -(s64)blen, ip->i_inode.i_uid, ip->i_inode.i_gid); | 1636 | gfs2_quota_change(ip, -(s64)blen, ip->i_inode.i_uid, ip->i_inode.i_gid); |
1623 | } | 1637 | } |
@@ -1630,7 +1644,7 @@ void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) | |||
1630 | * | 1644 | * |
1631 | */ | 1645 | */ |
1632 | 1646 | ||
1633 | void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) | 1647 | void __gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) |
1634 | { | 1648 | { |
1635 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1649 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1636 | struct gfs2_rgrpd *rgd; | 1650 | struct gfs2_rgrpd *rgd; |
@@ -1645,10 +1659,24 @@ void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) | |||
1645 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); | 1659 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); |
1646 | 1660 | ||
1647 | gfs2_trans_add_rg(rgd); | 1661 | gfs2_trans_add_rg(rgd); |
1662 | gfs2_meta_wipe(ip, bstart, blen); | ||
1663 | } | ||
1648 | 1664 | ||
1665 | /** | ||
1666 | * gfs2_free_meta - free a contiguous run of data block(s) | ||
1667 | * @ip: the inode these blocks are being freed from | ||
1668 | * @bstart: first block of a run of contiguous blocks | ||
1669 | * @blen: the length of the block run | ||
1670 | * | ||
1671 | */ | ||
1672 | |||
1673 | void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) | ||
1674 | { | ||
1675 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
1676 | |||
1677 | __gfs2_free_meta(ip, bstart, blen); | ||
1649 | gfs2_statfs_change(sdp, 0, +blen, 0); | 1678 | gfs2_statfs_change(sdp, 0, +blen, 0); |
1650 | gfs2_quota_change(ip, -(s64)blen, ip->i_inode.i_uid, ip->i_inode.i_gid); | 1679 | gfs2_quota_change(ip, -(s64)blen, ip->i_inode.i_uid, ip->i_inode.i_gid); |
1651 | gfs2_meta_wipe(ip, bstart, blen); | ||
1652 | } | 1680 | } |
1653 | 1681 | ||
1654 | void gfs2_unlink_di(struct inode *inode) | 1682 | void gfs2_unlink_di(struct inode *inode) |
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 50c2bb04369..a80e3034ac4 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h | |||
@@ -52,7 +52,9 @@ extern int gfs2_ri_update(struct gfs2_inode *ip); | |||
52 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n); | 52 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n); |
53 | extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation); | 53 | extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation); |
54 | 54 | ||
55 | extern void __gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); | ||
55 | extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); | 56 | extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); |
57 | extern void __gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); | ||
56 | extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); | 58 | extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); |
57 | extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); | 59 | extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); |
58 | extern void gfs2_unlink_di(struct inode *inode); | 60 | extern void gfs2_unlink_di(struct inode *inode); |