diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/aops.c | 39 | ||||
-rw-r--r-- | fs/gfs2/glock.c | 138 | ||||
-rw-r--r-- | fs/gfs2/glock.h | 3 | ||||
-rw-r--r-- | fs/gfs2/glops.c | 21 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 2 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 23 | ||||
-rw-r--r-- | fs/gfs2/super.c | 40 | ||||
-rw-r--r-- | fs/gfs2/super.h | 4 |
8 files changed, 195 insertions, 75 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 03ebb439ace0..7ebae9a4ecc0 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c | |||
@@ -624,6 +624,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, | |||
624 | { | 624 | { |
625 | struct gfs2_inode *ip = GFS2_I(mapping->host); | 625 | struct gfs2_inode *ip = GFS2_I(mapping->host); |
626 | struct gfs2_sbd *sdp = GFS2_SB(mapping->host); | 626 | struct gfs2_sbd *sdp = GFS2_SB(mapping->host); |
627 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
627 | unsigned int data_blocks = 0, ind_blocks = 0, rblocks; | 628 | unsigned int data_blocks = 0, ind_blocks = 0, rblocks; |
628 | int alloc_required; | 629 | int alloc_required; |
629 | int error = 0; | 630 | int error = 0; |
@@ -637,6 +638,14 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, | |||
637 | error = gfs2_glock_nq(&ip->i_gh); | 638 | error = gfs2_glock_nq(&ip->i_gh); |
638 | if (unlikely(error)) | 639 | if (unlikely(error)) |
639 | goto out_uninit; | 640 | goto out_uninit; |
641 | if (&ip->i_inode == sdp->sd_rindex) { | ||
642 | error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, | ||
643 | GL_NOCACHE, &m_ip->i_gh); | ||
644 | if (unlikely(error)) { | ||
645 | gfs2_glock_dq(&ip->i_gh); | ||
646 | goto out_uninit; | ||
647 | } | ||
648 | } | ||
640 | 649 | ||
641 | error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); | 650 | error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); |
642 | if (error) | 651 | if (error) |
@@ -667,6 +676,8 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, | |||
667 | rblocks += data_blocks ? data_blocks : 1; | 676 | rblocks += data_blocks ? data_blocks : 1; |
668 | if (ind_blocks || data_blocks) | 677 | if (ind_blocks || data_blocks) |
669 | rblocks += RES_STATFS + RES_QUOTA; | 678 | rblocks += RES_STATFS + RES_QUOTA; |
679 | if (&ip->i_inode == sdp->sd_rindex) | ||
680 | rblocks += 2 * RES_STATFS; | ||
670 | 681 | ||
671 | error = gfs2_trans_begin(sdp, rblocks, | 682 | error = gfs2_trans_begin(sdp, rblocks, |
672 | PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); | 683 | PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); |
@@ -712,6 +723,10 @@ out_alloc_put: | |||
712 | gfs2_alloc_put(ip); | 723 | gfs2_alloc_put(ip); |
713 | } | 724 | } |
714 | out_unlock: | 725 | out_unlock: |
726 | if (&ip->i_inode == sdp->sd_rindex) { | ||
727 | gfs2_glock_dq(&m_ip->i_gh); | ||
728 | gfs2_holder_uninit(&m_ip->i_gh); | ||
729 | } | ||
715 | gfs2_glock_dq(&ip->i_gh); | 730 | gfs2_glock_dq(&ip->i_gh); |
716 | out_uninit: | 731 | out_uninit: |
717 | gfs2_holder_uninit(&ip->i_gh); | 732 | gfs2_holder_uninit(&ip->i_gh); |
@@ -725,14 +740,21 @@ out_uninit: | |||
725 | static void adjust_fs_space(struct inode *inode) | 740 | static void adjust_fs_space(struct inode *inode) |
726 | { | 741 | { |
727 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | 742 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; |
743 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
744 | struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); | ||
728 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; | 745 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; |
729 | struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; | 746 | struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; |
747 | struct buffer_head *m_bh, *l_bh; | ||
730 | u64 fs_total, new_free; | 748 | u64 fs_total, new_free; |
731 | 749 | ||
732 | /* Total up the file system space, according to the latest rindex. */ | 750 | /* Total up the file system space, according to the latest rindex. */ |
733 | fs_total = gfs2_ri_total(sdp); | 751 | fs_total = gfs2_ri_total(sdp); |
752 | if (gfs2_meta_inode_buffer(m_ip, &m_bh) != 0) | ||
753 | return; | ||
734 | 754 | ||
735 | spin_lock(&sdp->sd_statfs_spin); | 755 | spin_lock(&sdp->sd_statfs_spin); |
756 | gfs2_statfs_change_in(m_sc, m_bh->b_data + | ||
757 | sizeof(struct gfs2_dinode)); | ||
736 | if (fs_total > (m_sc->sc_total + l_sc->sc_total)) | 758 | if (fs_total > (m_sc->sc_total + l_sc->sc_total)) |
737 | new_free = fs_total - (m_sc->sc_total + l_sc->sc_total); | 759 | new_free = fs_total - (m_sc->sc_total + l_sc->sc_total); |
738 | else | 760 | else |
@@ -741,6 +763,13 @@ static void adjust_fs_space(struct inode *inode) | |||
741 | fs_warn(sdp, "File system extended by %llu blocks.\n", | 763 | fs_warn(sdp, "File system extended by %llu blocks.\n", |
742 | (unsigned long long)new_free); | 764 | (unsigned long long)new_free); |
743 | gfs2_statfs_change(sdp, new_free, new_free, 0); | 765 | gfs2_statfs_change(sdp, new_free, new_free, 0); |
766 | |||
767 | if (gfs2_meta_inode_buffer(l_ip, &l_bh) != 0) | ||
768 | goto out; | ||
769 | update_statfs(sdp, m_bh, l_bh); | ||
770 | brelse(l_bh); | ||
771 | out: | ||
772 | brelse(m_bh); | ||
744 | } | 773 | } |
745 | 774 | ||
746 | /** | 775 | /** |
@@ -763,6 +792,7 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, | |||
763 | { | 792 | { |
764 | struct gfs2_inode *ip = GFS2_I(inode); | 793 | struct gfs2_inode *ip = GFS2_I(inode); |
765 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 794 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
795 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
766 | u64 to = pos + copied; | 796 | u64 to = pos + copied; |
767 | void *kaddr; | 797 | void *kaddr; |
768 | unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); | 798 | unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); |
@@ -794,6 +824,10 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, | |||
794 | 824 | ||
795 | brelse(dibh); | 825 | brelse(dibh); |
796 | gfs2_trans_end(sdp); | 826 | gfs2_trans_end(sdp); |
827 | if (inode == sdp->sd_rindex) { | ||
828 | gfs2_glock_dq(&m_ip->i_gh); | ||
829 | gfs2_holder_uninit(&m_ip->i_gh); | ||
830 | } | ||
797 | gfs2_glock_dq(&ip->i_gh); | 831 | gfs2_glock_dq(&ip->i_gh); |
798 | gfs2_holder_uninit(&ip->i_gh); | 832 | gfs2_holder_uninit(&ip->i_gh); |
799 | return copied; | 833 | return copied; |
@@ -823,6 +857,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, | |||
823 | struct inode *inode = page->mapping->host; | 857 | struct inode *inode = page->mapping->host; |
824 | struct gfs2_inode *ip = GFS2_I(inode); | 858 | struct gfs2_inode *ip = GFS2_I(inode); |
825 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 859 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
860 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
826 | struct buffer_head *dibh; | 861 | struct buffer_head *dibh; |
827 | struct gfs2_alloc *al = ip->i_alloc; | 862 | struct gfs2_alloc *al = ip->i_alloc; |
828 | unsigned int from = pos & (PAGE_CACHE_SIZE - 1); | 863 | unsigned int from = pos & (PAGE_CACHE_SIZE - 1); |
@@ -865,6 +900,10 @@ failed: | |||
865 | gfs2_quota_unlock(ip); | 900 | gfs2_quota_unlock(ip); |
866 | gfs2_alloc_put(ip); | 901 | gfs2_alloc_put(ip); |
867 | } | 902 | } |
903 | if (inode == sdp->sd_rindex) { | ||
904 | gfs2_glock_dq(&m_ip->i_gh); | ||
905 | gfs2_holder_uninit(&m_ip->i_gh); | ||
906 | } | ||
868 | gfs2_glock_dq(&ip->i_gh); | 907 | gfs2_glock_dq(&ip->i_gh); |
869 | gfs2_holder_uninit(&ip->i_gh); | 908 | gfs2_holder_uninit(&ip->i_gh); |
870 | return ret; | 909 | return ret; |
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 297421c0427a..8b674b1f3a55 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -63,6 +63,7 @@ static void do_xmote(struct gfs2_glock *gl, struct gfs2_holder *gh, unsigned int | |||
63 | static DECLARE_RWSEM(gfs2_umount_flush_sem); | 63 | static DECLARE_RWSEM(gfs2_umount_flush_sem); |
64 | static struct dentry *gfs2_root; | 64 | static struct dentry *gfs2_root; |
65 | static struct workqueue_struct *glock_workqueue; | 65 | static struct workqueue_struct *glock_workqueue; |
66 | struct workqueue_struct *gfs2_delete_workqueue; | ||
66 | static LIST_HEAD(lru_list); | 67 | static LIST_HEAD(lru_list); |
67 | static atomic_t lru_count = ATOMIC_INIT(0); | 68 | static atomic_t lru_count = ATOMIC_INIT(0); |
68 | static DEFINE_SPINLOCK(lru_lock); | 69 | static DEFINE_SPINLOCK(lru_lock); |
@@ -167,13 +168,33 @@ static void glock_free(struct gfs2_glock *gl) | |||
167 | * | 168 | * |
168 | */ | 169 | */ |
169 | 170 | ||
170 | static void gfs2_glock_hold(struct gfs2_glock *gl) | 171 | void gfs2_glock_hold(struct gfs2_glock *gl) |
171 | { | 172 | { |
172 | GLOCK_BUG_ON(gl, atomic_read(&gl->gl_ref) == 0); | 173 | GLOCK_BUG_ON(gl, atomic_read(&gl->gl_ref) == 0); |
173 | atomic_inc(&gl->gl_ref); | 174 | atomic_inc(&gl->gl_ref); |
174 | } | 175 | } |
175 | 176 | ||
176 | /** | 177 | /** |
178 | * demote_ok - Check to see if it's ok to unlock a glock | ||
179 | * @gl: the glock | ||
180 | * | ||
181 | * Returns: 1 if it's ok | ||
182 | */ | ||
183 | |||
184 | static int demote_ok(const struct gfs2_glock *gl) | ||
185 | { | ||
186 | const struct gfs2_glock_operations *glops = gl->gl_ops; | ||
187 | |||
188 | if (gl->gl_state == LM_ST_UNLOCKED) | ||
189 | return 0; | ||
190 | if (!list_empty(&gl->gl_holders)) | ||
191 | return 0; | ||
192 | if (glops->go_demote_ok) | ||
193 | return glops->go_demote_ok(gl); | ||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | /** | ||
177 | * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list | 198 | * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list |
178 | * @gl: the glock | 199 | * @gl: the glock |
179 | * | 200 | * |
@@ -181,8 +202,13 @@ static void gfs2_glock_hold(struct gfs2_glock *gl) | |||
181 | 202 | ||
182 | static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) | 203 | static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) |
183 | { | 204 | { |
205 | int may_reclaim; | ||
206 | may_reclaim = (demote_ok(gl) && | ||
207 | (atomic_read(&gl->gl_ref) == 1 || | ||
208 | (gl->gl_name.ln_type == LM_TYPE_INODE && | ||
209 | atomic_read(&gl->gl_ref) <= 2))); | ||
184 | spin_lock(&lru_lock); | 210 | spin_lock(&lru_lock); |
185 | if (list_empty(&gl->gl_lru) && gl->gl_state != LM_ST_UNLOCKED) { | 211 | if (list_empty(&gl->gl_lru) && may_reclaim) { |
186 | list_add_tail(&gl->gl_lru, &lru_list); | 212 | list_add_tail(&gl->gl_lru, &lru_list); |
187 | atomic_inc(&lru_count); | 213 | atomic_inc(&lru_count); |
188 | } | 214 | } |
@@ -190,6 +216,21 @@ static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) | |||
190 | } | 216 | } |
191 | 217 | ||
192 | /** | 218 | /** |
219 | * gfs2_glock_put_nolock() - Decrement reference count on glock | ||
220 | * @gl: The glock to put | ||
221 | * | ||
222 | * This function should only be used if the caller has its own reference | ||
223 | * to the glock, in addition to the one it is dropping. | ||
224 | */ | ||
225 | |||
226 | void gfs2_glock_put_nolock(struct gfs2_glock *gl) | ||
227 | { | ||
228 | if (atomic_dec_and_test(&gl->gl_ref)) | ||
229 | GLOCK_BUG_ON(gl, 1); | ||
230 | gfs2_glock_schedule_for_reclaim(gl); | ||
231 | } | ||
232 | |||
233 | /** | ||
193 | * gfs2_glock_put() - Decrement reference count on glock | 234 | * gfs2_glock_put() - Decrement reference count on glock |
194 | * @gl: The glock to put | 235 | * @gl: The glock to put |
195 | * | 236 | * |
@@ -214,9 +255,9 @@ int gfs2_glock_put(struct gfs2_glock *gl) | |||
214 | rv = 1; | 255 | rv = 1; |
215 | goto out; | 256 | goto out; |
216 | } | 257 | } |
217 | /* 1 for being hashed, 1 for having state != LM_ST_UNLOCKED */ | 258 | spin_lock(&gl->gl_spin); |
218 | if (atomic_read(&gl->gl_ref) == 2) | 259 | gfs2_glock_schedule_for_reclaim(gl); |
219 | gfs2_glock_schedule_for_reclaim(gl); | 260 | spin_unlock(&gl->gl_spin); |
220 | write_unlock(gl_lock_addr(gl->gl_hash)); | 261 | write_unlock(gl_lock_addr(gl->gl_hash)); |
221 | out: | 262 | out: |
222 | return rv; | 263 | return rv; |
@@ -398,7 +439,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) | |||
398 | if (held2) | 439 | if (held2) |
399 | gfs2_glock_hold(gl); | 440 | gfs2_glock_hold(gl); |
400 | else | 441 | else |
401 | gfs2_glock_put(gl); | 442 | gfs2_glock_put_nolock(gl); |
402 | } | 443 | } |
403 | 444 | ||
404 | gl->gl_state = new_state; | 445 | gl->gl_state = new_state; |
@@ -633,12 +674,35 @@ out: | |||
633 | out_sched: | 674 | out_sched: |
634 | gfs2_glock_hold(gl); | 675 | gfs2_glock_hold(gl); |
635 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | 676 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) |
636 | gfs2_glock_put(gl); | 677 | gfs2_glock_put_nolock(gl); |
637 | out_unlock: | 678 | out_unlock: |
638 | clear_bit(GLF_LOCK, &gl->gl_flags); | 679 | clear_bit(GLF_LOCK, &gl->gl_flags); |
639 | goto out; | 680 | goto out; |
640 | } | 681 | } |
641 | 682 | ||
683 | static void delete_work_func(struct work_struct *work) | ||
684 | { | ||
685 | struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete); | ||
686 | struct gfs2_sbd *sdp = gl->gl_sbd; | ||
687 | struct gfs2_inode *ip = NULL; | ||
688 | struct inode *inode; | ||
689 | u64 no_addr = 0; | ||
690 | |||
691 | spin_lock(&gl->gl_spin); | ||
692 | ip = (struct gfs2_inode *)gl->gl_object; | ||
693 | if (ip) | ||
694 | no_addr = ip->i_no_addr; | ||
695 | spin_unlock(&gl->gl_spin); | ||
696 | if (ip) { | ||
697 | inode = gfs2_ilookup(sdp->sd_vfs, no_addr); | ||
698 | if (inode) { | ||
699 | d_prune_aliases(inode); | ||
700 | iput(inode); | ||
701 | } | ||
702 | } | ||
703 | gfs2_glock_put(gl); | ||
704 | } | ||
705 | |||
642 | static void glock_work_func(struct work_struct *work) | 706 | static void glock_work_func(struct work_struct *work) |
643 | { | 707 | { |
644 | unsigned long delay = 0; | 708 | unsigned long delay = 0; |
@@ -717,6 +781,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, | |||
717 | gl->gl_sbd = sdp; | 781 | gl->gl_sbd = sdp; |
718 | gl->gl_aspace = NULL; | 782 | gl->gl_aspace = NULL; |
719 | INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); | 783 | INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); |
784 | INIT_WORK(&gl->gl_delete, delete_work_func); | ||
720 | 785 | ||
721 | /* If this glock protects actual on-disk data or metadata blocks, | 786 | /* If this glock protects actual on-disk data or metadata blocks, |
722 | create a VFS inode to manage the pages/buffers holding them. */ | 787 | create a VFS inode to manage the pages/buffers holding them. */ |
@@ -858,6 +923,8 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, | |||
858 | gl->gl_demote_state != state) { | 923 | gl->gl_demote_state != state) { |
859 | gl->gl_demote_state = LM_ST_UNLOCKED; | 924 | gl->gl_demote_state = LM_ST_UNLOCKED; |
860 | } | 925 | } |
926 | if (gl->gl_ops->go_callback) | ||
927 | gl->gl_ops->go_callback(gl); | ||
861 | trace_gfs2_demote_rq(gl); | 928 | trace_gfs2_demote_rq(gl); |
862 | } | 929 | } |
863 | 930 | ||
@@ -1274,33 +1341,12 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret) | |||
1274 | gfs2_glock_put(gl); | 1341 | gfs2_glock_put(gl); |
1275 | } | 1342 | } |
1276 | 1343 | ||
1277 | /** | ||
1278 | * demote_ok - Check to see if it's ok to unlock a glock | ||
1279 | * @gl: the glock | ||
1280 | * | ||
1281 | * Returns: 1 if it's ok | ||
1282 | */ | ||
1283 | |||
1284 | static int demote_ok(const struct gfs2_glock *gl) | ||
1285 | { | ||
1286 | const struct gfs2_glock_operations *glops = gl->gl_ops; | ||
1287 | |||
1288 | if (gl->gl_state == LM_ST_UNLOCKED) | ||
1289 | return 0; | ||
1290 | if (!list_empty(&gl->gl_holders)) | ||
1291 | return 0; | ||
1292 | if (glops->go_demote_ok) | ||
1293 | return glops->go_demote_ok(gl); | ||
1294 | return 1; | ||
1295 | } | ||
1296 | |||
1297 | 1344 | ||
1298 | static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) | 1345 | static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) |
1299 | { | 1346 | { |
1300 | struct gfs2_glock *gl; | 1347 | struct gfs2_glock *gl; |
1301 | int may_demote; | 1348 | int may_demote; |
1302 | int nr_skipped = 0; | 1349 | int nr_skipped = 0; |
1303 | int got_ref = 0; | ||
1304 | LIST_HEAD(skipped); | 1350 | LIST_HEAD(skipped); |
1305 | 1351 | ||
1306 | if (nr == 0) | 1352 | if (nr == 0) |
@@ -1315,37 +1361,29 @@ static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) | |||
1315 | list_del_init(&gl->gl_lru); | 1361 | list_del_init(&gl->gl_lru); |
1316 | atomic_dec(&lru_count); | 1362 | atomic_dec(&lru_count); |
1317 | 1363 | ||
1364 | /* Check if glock is about to be freed */ | ||
1365 | if (atomic_read(&gl->gl_ref) == 0) | ||
1366 | continue; | ||
1367 | |||
1318 | /* Test for being demotable */ | 1368 | /* Test for being demotable */ |
1319 | if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { | 1369 | if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { |
1320 | gfs2_glock_hold(gl); | 1370 | gfs2_glock_hold(gl); |
1321 | got_ref = 1; | ||
1322 | spin_unlock(&lru_lock); | 1371 | spin_unlock(&lru_lock); |
1323 | spin_lock(&gl->gl_spin); | 1372 | spin_lock(&gl->gl_spin); |
1324 | may_demote = demote_ok(gl); | 1373 | may_demote = demote_ok(gl); |
1325 | spin_unlock(&gl->gl_spin); | ||
1326 | clear_bit(GLF_LOCK, &gl->gl_flags); | ||
1327 | if (may_demote) { | 1374 | if (may_demote) { |
1328 | handle_callback(gl, LM_ST_UNLOCKED, 0); | 1375 | handle_callback(gl, LM_ST_UNLOCKED, 0); |
1329 | nr--; | 1376 | nr--; |
1330 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | ||
1331 | gfs2_glock_put(gl); | ||
1332 | got_ref = 0; | ||
1333 | } | 1377 | } |
1378 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | ||
1379 | gfs2_glock_put_nolock(gl); | ||
1380 | spin_unlock(&gl->gl_spin); | ||
1381 | clear_bit(GLF_LOCK, &gl->gl_flags); | ||
1334 | spin_lock(&lru_lock); | 1382 | spin_lock(&lru_lock); |
1335 | if (may_demote) | 1383 | continue; |
1336 | continue; | ||
1337 | } | ||
1338 | if (list_empty(&gl->gl_lru) && | ||
1339 | (atomic_read(&gl->gl_ref) <= (2 + got_ref))) { | ||
1340 | nr_skipped++; | ||
1341 | list_add(&gl->gl_lru, &skipped); | ||
1342 | } | ||
1343 | if (got_ref) { | ||
1344 | spin_unlock(&lru_lock); | ||
1345 | gfs2_glock_put(gl); | ||
1346 | spin_lock(&lru_lock); | ||
1347 | got_ref = 0; | ||
1348 | } | 1384 | } |
1385 | nr_skipped++; | ||
1386 | list_add(&gl->gl_lru, &skipped); | ||
1349 | } | 1387 | } |
1350 | list_splice(&skipped, &lru_list); | 1388 | list_splice(&skipped, &lru_list); |
1351 | atomic_add(nr_skipped, &lru_count); | 1389 | atomic_add(nr_skipped, &lru_count); |
@@ -1727,6 +1765,11 @@ int __init gfs2_glock_init(void) | |||
1727 | glock_workqueue = create_workqueue("glock_workqueue"); | 1765 | glock_workqueue = create_workqueue("glock_workqueue"); |
1728 | if (IS_ERR(glock_workqueue)) | 1766 | if (IS_ERR(glock_workqueue)) |
1729 | return PTR_ERR(glock_workqueue); | 1767 | return PTR_ERR(glock_workqueue); |
1768 | gfs2_delete_workqueue = create_workqueue("delete_workqueue"); | ||
1769 | if (IS_ERR(gfs2_delete_workqueue)) { | ||
1770 | destroy_workqueue(glock_workqueue); | ||
1771 | return PTR_ERR(gfs2_delete_workqueue); | ||
1772 | } | ||
1730 | 1773 | ||
1731 | register_shrinker(&glock_shrinker); | 1774 | register_shrinker(&glock_shrinker); |
1732 | 1775 | ||
@@ -1737,6 +1780,7 @@ void gfs2_glock_exit(void) | |||
1737 | { | 1780 | { |
1738 | unregister_shrinker(&glock_shrinker); | 1781 | unregister_shrinker(&glock_shrinker); |
1739 | destroy_workqueue(glock_workqueue); | 1782 | destroy_workqueue(glock_workqueue); |
1783 | destroy_workqueue(gfs2_delete_workqueue); | ||
1740 | } | 1784 | } |
1741 | 1785 | ||
1742 | static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) | 1786 | static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) |
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index a602a28f6f08..c609894ec0d0 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h | |||
@@ -143,6 +143,7 @@ struct lm_lockops { | |||
143 | 143 | ||
144 | #define GLR_TRYFAILED 13 | 144 | #define GLR_TRYFAILED 13 |
145 | 145 | ||
146 | extern struct workqueue_struct *gfs2_delete_workqueue; | ||
146 | static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) | 147 | static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) |
147 | { | 148 | { |
148 | struct gfs2_holder *gh; | 149 | struct gfs2_holder *gh; |
@@ -191,6 +192,8 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) | |||
191 | int gfs2_glock_get(struct gfs2_sbd *sdp, | 192 | int gfs2_glock_get(struct gfs2_sbd *sdp, |
192 | u64 number, const struct gfs2_glock_operations *glops, | 193 | u64 number, const struct gfs2_glock_operations *glops, |
193 | int create, struct gfs2_glock **glp); | 194 | int create, struct gfs2_glock **glp); |
195 | void gfs2_glock_hold(struct gfs2_glock *gl); | ||
196 | void gfs2_glock_put_nolock(struct gfs2_glock *gl); | ||
194 | int gfs2_glock_put(struct gfs2_glock *gl); | 197 | int gfs2_glock_put(struct gfs2_glock *gl); |
195 | void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, | 198 | void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, |
196 | struct gfs2_holder *gh); | 199 | struct gfs2_holder *gh); |
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index d5e4ab155ca0..6985eef06c39 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
@@ -323,6 +323,7 @@ static void trans_go_sync(struct gfs2_glock *gl) | |||
323 | 323 | ||
324 | if (gl->gl_state != LM_ST_UNLOCKED && | 324 | if (gl->gl_state != LM_ST_UNLOCKED && |
325 | test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { | 325 | test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { |
326 | flush_workqueue(gfs2_delete_workqueue); | ||
326 | gfs2_meta_syncfs(sdp); | 327 | gfs2_meta_syncfs(sdp); |
327 | gfs2_log_shutdown(sdp); | 328 | gfs2_log_shutdown(sdp); |
328 | } | 329 | } |
@@ -372,6 +373,25 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl) | |||
372 | return 0; | 373 | return 0; |
373 | } | 374 | } |
374 | 375 | ||
376 | /** | ||
377 | * iopen_go_callback - schedule the dcache entry for the inode to be deleted | ||
378 | * @gl: the glock | ||
379 | * | ||
380 | * gl_spin lock is held while calling this | ||
381 | */ | ||
382 | static void iopen_go_callback(struct gfs2_glock *gl) | ||
383 | { | ||
384 | struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object; | ||
385 | |||
386 | if (gl->gl_demote_state == LM_ST_UNLOCKED && | ||
387 | gl->gl_state == LM_ST_SHARED && | ||
388 | ip && test_bit(GIF_USER, &ip->i_flags)) { | ||
389 | gfs2_glock_hold(gl); | ||
390 | if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0) | ||
391 | gfs2_glock_put_nolock(gl); | ||
392 | } | ||
393 | } | ||
394 | |||
375 | const struct gfs2_glock_operations gfs2_meta_glops = { | 395 | const struct gfs2_glock_operations gfs2_meta_glops = { |
376 | .go_type = LM_TYPE_META, | 396 | .go_type = LM_TYPE_META, |
377 | }; | 397 | }; |
@@ -406,6 +426,7 @@ const struct gfs2_glock_operations gfs2_trans_glops = { | |||
406 | 426 | ||
407 | const struct gfs2_glock_operations gfs2_iopen_glops = { | 427 | const struct gfs2_glock_operations gfs2_iopen_glops = { |
408 | .go_type = LM_TYPE_IOPEN, | 428 | .go_type = LM_TYPE_IOPEN, |
429 | .go_callback = iopen_go_callback, | ||
409 | }; | 430 | }; |
410 | 431 | ||
411 | const struct gfs2_glock_operations gfs2_flock_glops = { | 432 | const struct gfs2_glock_operations gfs2_flock_glops = { |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 225347fbff3c..61801ada36f0 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -159,6 +159,7 @@ struct gfs2_glock_operations { | |||
159 | int (*go_lock) (struct gfs2_holder *gh); | 159 | int (*go_lock) (struct gfs2_holder *gh); |
160 | void (*go_unlock) (struct gfs2_holder *gh); | 160 | void (*go_unlock) (struct gfs2_holder *gh); |
161 | int (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl); | 161 | int (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl); |
162 | void (*go_callback) (struct gfs2_glock *gl); | ||
162 | const int go_type; | 163 | const int go_type; |
163 | const unsigned long go_min_hold_time; | 164 | const unsigned long go_min_hold_time; |
164 | }; | 165 | }; |
@@ -228,6 +229,7 @@ struct gfs2_glock { | |||
228 | struct list_head gl_ail_list; | 229 | struct list_head gl_ail_list; |
229 | atomic_t gl_ail_count; | 230 | atomic_t gl_ail_count; |
230 | struct delayed_work gl_work; | 231 | struct delayed_work gl_work; |
232 | struct work_struct gl_delete; | ||
231 | }; | 233 | }; |
232 | 234 | ||
233 | #define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */ | 235 | #define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */ |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index daa4ae341a29..fba795798d3a 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -285,27 +285,19 @@ void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd) | |||
285 | } | 285 | } |
286 | 286 | ||
287 | tmp = rgd->rd_data - rgd->rd_free - rgd->rd_dinodes; | 287 | tmp = rgd->rd_data - rgd->rd_free - rgd->rd_dinodes; |
288 | if (count[1] + count[2] != tmp) { | 288 | if (count[1] != tmp) { |
289 | if (gfs2_consist_rgrpd(rgd)) | 289 | if (gfs2_consist_rgrpd(rgd)) |
290 | fs_err(sdp, "used data mismatch: %u != %u\n", | 290 | fs_err(sdp, "used data mismatch: %u != %u\n", |
291 | count[1], tmp); | 291 | count[1], tmp); |
292 | return; | 292 | return; |
293 | } | 293 | } |
294 | 294 | ||
295 | if (count[3] != rgd->rd_dinodes) { | 295 | if (count[2] + count[3] != rgd->rd_dinodes) { |
296 | if (gfs2_consist_rgrpd(rgd)) | 296 | if (gfs2_consist_rgrpd(rgd)) |
297 | fs_err(sdp, "used metadata mismatch: %u != %u\n", | 297 | fs_err(sdp, "used metadata mismatch: %u != %u\n", |
298 | count[3], rgd->rd_dinodes); | 298 | count[2] + count[3], rgd->rd_dinodes); |
299 | return; | 299 | return; |
300 | } | 300 | } |
301 | |||
302 | if (count[2] > count[3]) { | ||
303 | if (gfs2_consist_rgrpd(rgd)) | ||
304 | fs_err(sdp, "unlinked inodes > inodes: %u\n", | ||
305 | count[2]); | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | } | 301 | } |
310 | 302 | ||
311 | static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block) | 303 | static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block) |
@@ -961,7 +953,8 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) | |||
961 | * Returns: The inode, if one has been found | 953 | * Returns: The inode, if one has been found |
962 | */ | 954 | */ |
963 | 955 | ||
964 | static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) | 956 | static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, |
957 | u64 skip) | ||
965 | { | 958 | { |
966 | struct inode *inode; | 959 | struct inode *inode; |
967 | u32 goal = 0, block; | 960 | u32 goal = 0, block; |
@@ -985,6 +978,8 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) | |||
985 | goal++; | 978 | goal++; |
986 | if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked) | 979 | if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked) |
987 | continue; | 980 | continue; |
981 | if (no_addr == skip) | ||
982 | continue; | ||
988 | *last_unlinked = no_addr; | 983 | *last_unlinked = no_addr; |
989 | inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, | 984 | inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, |
990 | no_addr, -1, 1); | 985 | no_addr, -1, 1); |
@@ -1104,7 +1099,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1104 | if (try_rgrp_fit(rgd, al)) | 1099 | if (try_rgrp_fit(rgd, al)) |
1105 | goto out; | 1100 | goto out; |
1106 | if (rgd->rd_flags & GFS2_RDF_CHECK) | 1101 | if (rgd->rd_flags & GFS2_RDF_CHECK) |
1107 | inode = try_rgrp_unlink(rgd, last_unlinked); | 1102 | inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr); |
1108 | if (!rg_locked) | 1103 | if (!rg_locked) |
1109 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1104 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1110 | if (inode) | 1105 | if (inode) |
@@ -1138,7 +1133,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1138 | if (try_rgrp_fit(rgd, al)) | 1133 | if (try_rgrp_fit(rgd, al)) |
1139 | goto out; | 1134 | goto out; |
1140 | if (rgd->rd_flags & GFS2_RDF_CHECK) | 1135 | if (rgd->rd_flags & GFS2_RDF_CHECK) |
1141 | inode = try_rgrp_unlink(rgd, last_unlinked); | 1136 | inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr); |
1142 | if (!rg_locked) | 1137 | if (!rg_locked) |
1143 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1138 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1144 | if (inode) | 1139 | if (inode) |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 0a6801336470..f522bb017973 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
@@ -353,7 +353,7 @@ fail: | |||
353 | return error; | 353 | return error; |
354 | } | 354 | } |
355 | 355 | ||
356 | static void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf) | 356 | void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf) |
357 | { | 357 | { |
358 | const struct gfs2_statfs_change *str = buf; | 358 | const struct gfs2_statfs_change *str = buf; |
359 | 359 | ||
@@ -441,6 +441,29 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, | |||
441 | brelse(l_bh); | 441 | brelse(l_bh); |
442 | } | 442 | } |
443 | 443 | ||
444 | void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, | ||
445 | struct buffer_head *l_bh) | ||
446 | { | ||
447 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
448 | struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); | ||
449 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; | ||
450 | struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; | ||
451 | |||
452 | gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); | ||
453 | |||
454 | spin_lock(&sdp->sd_statfs_spin); | ||
455 | m_sc->sc_total += l_sc->sc_total; | ||
456 | m_sc->sc_free += l_sc->sc_free; | ||
457 | m_sc->sc_dinodes += l_sc->sc_dinodes; | ||
458 | memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); | ||
459 | memset(l_bh->b_data + sizeof(struct gfs2_dinode), | ||
460 | 0, sizeof(struct gfs2_statfs_change)); | ||
461 | spin_unlock(&sdp->sd_statfs_spin); | ||
462 | |||
463 | gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); | ||
464 | gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); | ||
465 | } | ||
466 | |||
444 | int gfs2_statfs_sync(struct gfs2_sbd *sdp) | 467 | int gfs2_statfs_sync(struct gfs2_sbd *sdp) |
445 | { | 468 | { |
446 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | 469 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); |
@@ -477,19 +500,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) | |||
477 | if (error) | 500 | if (error) |
478 | goto out_bh2; | 501 | goto out_bh2; |
479 | 502 | ||
480 | gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); | 503 | update_statfs(sdp, m_bh, l_bh); |
481 | |||
482 | spin_lock(&sdp->sd_statfs_spin); | ||
483 | m_sc->sc_total += l_sc->sc_total; | ||
484 | m_sc->sc_free += l_sc->sc_free; | ||
485 | m_sc->sc_dinodes += l_sc->sc_dinodes; | ||
486 | memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); | ||
487 | memset(l_bh->b_data + sizeof(struct gfs2_dinode), | ||
488 | 0, sizeof(struct gfs2_statfs_change)); | ||
489 | spin_unlock(&sdp->sd_statfs_spin); | ||
490 | |||
491 | gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); | ||
492 | gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); | ||
493 | 504 | ||
494 | gfs2_trans_end(sdp); | 505 | gfs2_trans_end(sdp); |
495 | 506 | ||
@@ -680,6 +691,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) | |||
680 | struct gfs2_holder t_gh; | 691 | struct gfs2_holder t_gh; |
681 | int error; | 692 | int error; |
682 | 693 | ||
694 | flush_workqueue(gfs2_delete_workqueue); | ||
683 | gfs2_quota_sync(sdp); | 695 | gfs2_quota_sync(sdp); |
684 | gfs2_statfs_sync(sdp); | 696 | gfs2_statfs_sync(sdp); |
685 | 697 | ||
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index b56413e3e40d..22e0417ed996 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h | |||
@@ -40,6 +40,10 @@ extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); | |||
40 | extern int gfs2_statfs_init(struct gfs2_sbd *sdp); | 40 | extern int gfs2_statfs_init(struct gfs2_sbd *sdp); |
41 | extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, | 41 | extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, |
42 | s64 dinodes); | 42 | s64 dinodes); |
43 | extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, | ||
44 | const void *buf); | ||
45 | extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, | ||
46 | struct buffer_head *l_bh); | ||
43 | extern int gfs2_statfs_sync(struct gfs2_sbd *sdp); | 47 | extern int gfs2_statfs_sync(struct gfs2_sbd *sdp); |
44 | 48 | ||
45 | extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); | 49 | extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); |