diff options
-rw-r--r-- | fs/gfs2/inode.c | 46 | ||||
-rw-r--r-- | fs/gfs2/meta_io.c | 112 | ||||
-rw-r--r-- | fs/gfs2/ondisk.c | 6 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 111 | ||||
-rw-r--r-- | fs/gfs2/ops_address.h | 1 | ||||
-rw-r--r-- | fs/gfs2/ops_file.c | 2 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 12 | ||||
-rw-r--r-- | fs/gfs2/rgrp.h | 6 | ||||
-rw-r--r-- | include/linux/gfs2_ondisk.h | 6 |
9 files changed, 153 insertions, 149 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f4c48395208a..22ca3b5ddaea 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -38,15 +38,17 @@ | |||
38 | #include "util.h" | 38 | #include "util.h" |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * inode_attr_in - Copy attributes from the dinode into the VFS inode | 41 | * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode |
42 | * @ip: The GFS2 inode (with embedded disk inode data) | 42 | * @ip: The GFS2 inode (with embedded disk inode data) |
43 | * @inode: The Linux VFS inode | 43 | * @inode: The Linux VFS inode |
44 | * | 44 | * |
45 | */ | 45 | */ |
46 | 46 | ||
47 | static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode) | 47 | void gfs2_inode_attr_in(struct gfs2_inode *ip) |
48 | { | 48 | { |
49 | inode->i_ino = ip->i_num.no_formal_ino; | 49 | struct inode *inode = &ip->i_inode; |
50 | |||
51 | inode->i_ino = ip->i_num.no_addr; | ||
50 | 52 | ||
51 | switch (ip->i_di.di_mode & S_IFMT) { | 53 | switch (ip->i_di.di_mode & S_IFMT) { |
52 | case S_IFBLK: | 54 | case S_IFBLK: |
@@ -85,18 +87,6 @@ static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode) | |||
85 | } | 87 | } |
86 | 88 | ||
87 | /** | 89 | /** |
88 | * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode | ||
89 | * @ip: The GFS2 inode (with embedded disk inode data) | ||
90 | * | ||
91 | */ | ||
92 | |||
93 | void gfs2_inode_attr_in(struct gfs2_inode *ip) | ||
94 | { | ||
95 | struct inode *inode = &ip->i_inode; | ||
96 | inode_attr_in(ip, inode); | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode | 90 | * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode |
101 | * @ip: The GFS2 inode | 91 | * @ip: The GFS2 inode |
102 | * | 92 | * |
@@ -621,7 +611,8 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, | |||
621 | *gid = current->fsgid; | 611 | *gid = current->fsgid; |
622 | } | 612 | } |
623 | 613 | ||
624 | static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum) | 614 | static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum, |
615 | u64 *generation) | ||
625 | { | 616 | { |
626 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 617 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
627 | int error; | 618 | int error; |
@@ -637,14 +628,14 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum) | |||
637 | if (error) | 628 | if (error) |
638 | goto out_ipreserv; | 629 | goto out_ipreserv; |
639 | 630 | ||
640 | inum->no_addr = gfs2_alloc_di(dip); | 631 | inum->no_addr = gfs2_alloc_di(dip, generation); |
641 | 632 | ||
642 | gfs2_trans_end(sdp); | 633 | gfs2_trans_end(sdp); |
643 | 634 | ||
644 | out_ipreserv: | 635 | out_ipreserv: |
645 | gfs2_inplace_release(dip); | 636 | gfs2_inplace_release(dip); |
646 | 637 | ||
647 | out: | 638 | out: |
648 | gfs2_alloc_put(dip); | 639 | gfs2_alloc_put(dip); |
649 | 640 | ||
650 | return error; | 641 | return error; |
@@ -662,8 +653,9 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum) | |||
662 | */ | 653 | */ |
663 | 654 | ||
664 | static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | 655 | static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, |
665 | struct gfs2_inum *inum, unsigned int mode, | 656 | const struct gfs2_inum *inum, unsigned int mode, |
666 | unsigned int uid, unsigned int gid) | 657 | unsigned int uid, unsigned int gid, |
658 | const u64 *generation) | ||
667 | { | 659 | { |
668 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 660 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
669 | struct gfs2_dinode *di; | 661 | struct gfs2_dinode *di; |
@@ -686,7 +678,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | |||
686 | di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds()); | 678 | di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds()); |
687 | di->di_major = di->di_minor = cpu_to_be32(0); | 679 | di->di_major = di->di_minor = cpu_to_be32(0); |
688 | di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); | 680 | di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); |
689 | di->__pad[0] = di->__pad[1] = 0; | 681 | di->di_generation = cpu_to_be64(*generation); |
690 | di->di_flags = cpu_to_be32(0); | 682 | di->di_flags = cpu_to_be32(0); |
691 | 683 | ||
692 | if (S_ISREG(mode)) { | 684 | if (S_ISREG(mode)) { |
@@ -717,7 +709,8 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | |||
717 | } | 709 | } |
718 | 710 | ||
719 | static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | 711 | static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, |
720 | unsigned int mode, struct gfs2_inum *inum) | 712 | unsigned int mode, const struct gfs2_inum *inum, |
713 | const u64 *generation) | ||
721 | { | 714 | { |
722 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 715 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
723 | unsigned int uid, gid; | 716 | unsigned int uid, gid; |
@@ -738,7 +731,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | |||
738 | if (error) | 731 | if (error) |
739 | goto out_quota; | 732 | goto out_quota; |
740 | 733 | ||
741 | init_dinode(dip, gl, inum, mode, uid, gid); | 734 | init_dinode(dip, gl, inum, mode, uid, gid, generation); |
742 | gfs2_quota_change(dip, +1, uid, gid); | 735 | gfs2_quota_change(dip, +1, uid, gid); |
743 | gfs2_trans_end(sdp); | 736 | gfs2_trans_end(sdp); |
744 | 737 | ||
@@ -844,6 +837,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
844 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 837 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
845 | struct gfs2_inum inum; | 838 | struct gfs2_inum inum; |
846 | int error; | 839 | int error; |
840 | u64 generation; | ||
847 | 841 | ||
848 | if (!name->len || name->len > GFS2_FNAMESIZE) | 842 | if (!name->len || name->len > GFS2_FNAMESIZE) |
849 | return ERR_PTR(-ENAMETOOLONG); | 843 | return ERR_PTR(-ENAMETOOLONG); |
@@ -861,7 +855,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
861 | if (error) | 855 | if (error) |
862 | goto fail_gunlock; | 856 | goto fail_gunlock; |
863 | 857 | ||
864 | error = alloc_dinode(dip, &inum); | 858 | error = alloc_dinode(dip, &inum, &generation); |
865 | if (error) | 859 | if (error) |
866 | goto fail_gunlock; | 860 | goto fail_gunlock; |
867 | 861 | ||
@@ -893,7 +887,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
893 | goto fail_gunlock; | 887 | goto fail_gunlock; |
894 | } | 888 | } |
895 | 889 | ||
896 | error = make_dinode(dip, ghs[1].gh_gl, mode, &inum); | 890 | error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation); |
897 | if (error) | 891 | if (error) |
898 | goto fail_gunlock2; | 892 | goto fail_gunlock2; |
899 | 893 | ||
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index ddcd4dc1081d..cad44fd70d67 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "rgrp.h" | 31 | #include "rgrp.h" |
32 | #include "trans.h" | 32 | #include "trans.h" |
33 | #include "util.h" | 33 | #include "util.h" |
34 | #include "ops_address.h" | ||
34 | 35 | ||
35 | #define buffer_busy(bh) \ | 36 | #define buffer_busy(bh) \ |
36 | ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) | 37 | ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) |
@@ -50,118 +51,9 @@ static int gfs2_aspace_writepage(struct page *page, | |||
50 | return block_write_full_page(page, aspace_get_block, wbc); | 51 | return block_write_full_page(page, aspace_get_block, wbc); |
51 | } | 52 | } |
52 | 53 | ||
53 | /** | ||
54 | * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. | ||
55 | * @bh: the buffer we're stuck on | ||
56 | * | ||
57 | */ | ||
58 | |||
59 | static void stuck_releasepage(struct buffer_head *bh) | ||
60 | { | ||
61 | struct inode *inode = bh->b_page->mapping->host; | ||
62 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | ||
63 | struct gfs2_bufdata *bd = bh->b_private; | ||
64 | struct gfs2_glock *gl; | ||
65 | |||
66 | fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); | ||
67 | fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", | ||
68 | (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); | ||
69 | fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); | ||
70 | fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); | ||
71 | |||
72 | if (!bd) | ||
73 | return; | ||
74 | |||
75 | gl = bd->bd_gl; | ||
76 | |||
77 | fs_warn(sdp, "gl = (%u, %llu)\n", | ||
78 | gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); | ||
79 | |||
80 | fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", | ||
81 | (list_empty(&bd->bd_list_tr)) ? "no" : "yes", | ||
82 | (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); | ||
83 | |||
84 | if (gl->gl_ops == &gfs2_inode_glops) { | ||
85 | struct gfs2_inode *ip = gl->gl_object; | ||
86 | unsigned int x; | ||
87 | |||
88 | if (!ip) | ||
89 | return; | ||
90 | |||
91 | fs_warn(sdp, "ip = %llu %llu\n", | ||
92 | (unsigned long long)ip->i_num.no_formal_ino, | ||
93 | (unsigned long long)ip->i_num.no_addr); | ||
94 | |||
95 | for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) | ||
96 | fs_warn(sdp, "ip->i_cache[%u] = %s\n", | ||
97 | x, (ip->i_cache[x]) ? "!NULL" : "NULL"); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * gfs2_aspace_releasepage - free the metadata associated with a page | ||
103 | * @page: the page that's being released | ||
104 | * @gfp_mask: passed from Linux VFS, ignored by us | ||
105 | * | ||
106 | * Call try_to_free_buffers() if the buffers in this page can be | ||
107 | * released. | ||
108 | * | ||
109 | * Returns: 0 | ||
110 | */ | ||
111 | |||
112 | static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) | ||
113 | { | ||
114 | struct inode *aspace = page->mapping->host; | ||
115 | struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; | ||
116 | struct buffer_head *bh, *head; | ||
117 | struct gfs2_bufdata *bd; | ||
118 | unsigned long t; | ||
119 | |||
120 | if (!page_has_buffers(page)) | ||
121 | goto out; | ||
122 | |||
123 | head = bh = page_buffers(page); | ||
124 | do { | ||
125 | t = jiffies; | ||
126 | |||
127 | while (atomic_read(&bh->b_count)) { | ||
128 | if (atomic_read(&aspace->i_writecount)) { | ||
129 | if (time_after_eq(jiffies, t + | ||
130 | gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { | ||
131 | stuck_releasepage(bh); | ||
132 | t = jiffies; | ||
133 | } | ||
134 | |||
135 | yield(); | ||
136 | continue; | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | gfs2_assert_warn(sdp, !buffer_pinned(bh)); | ||
143 | |||
144 | bd = bh->b_private; | ||
145 | if (bd) { | ||
146 | gfs2_assert_warn(sdp, bd->bd_bh == bh); | ||
147 | gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); | ||
148 | gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); | ||
149 | gfs2_assert_warn(sdp, !bd->bd_ail); | ||
150 | kmem_cache_free(gfs2_bufdata_cachep, bd); | ||
151 | bh->b_private = NULL; | ||
152 | } | ||
153 | |||
154 | bh = bh->b_this_page; | ||
155 | } | ||
156 | while (bh != head); | ||
157 | |||
158 | out: | ||
159 | return try_to_free_buffers(page); | ||
160 | } | ||
161 | |||
162 | static const struct address_space_operations aspace_aops = { | 54 | static const struct address_space_operations aspace_aops = { |
163 | .writepage = gfs2_aspace_writepage, | 55 | .writepage = gfs2_aspace_writepage, |
164 | .releasepage = gfs2_aspace_releasepage, | 56 | .releasepage = gfs2_releasepage, |
165 | }; | 57 | }; |
166 | 58 | ||
167 | /** | 59 | /** |
diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c index 09154ad7b270..39c7f0345fc6 100644 --- a/fs/gfs2/ondisk.c +++ b/fs/gfs2/ondisk.c | |||
@@ -128,6 +128,7 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, char *buf) | |||
128 | rg->rg_flags = be32_to_cpu(str->rg_flags); | 128 | rg->rg_flags = be32_to_cpu(str->rg_flags); |
129 | rg->rg_free = be32_to_cpu(str->rg_free); | 129 | rg->rg_free = be32_to_cpu(str->rg_free); |
130 | rg->rg_dinodes = be32_to_cpu(str->rg_dinodes); | 130 | rg->rg_dinodes = be32_to_cpu(str->rg_dinodes); |
131 | rg->rg_igeneration = be64_to_cpu(str->rg_igeneration); | ||
131 | } | 132 | } |
132 | 133 | ||
133 | void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) | 134 | void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) |
@@ -138,7 +139,8 @@ void gfs2_rgrp_out(struct gfs2_rgrp *rg, char *buf) | |||
138 | str->rg_flags = cpu_to_be32(rg->rg_flags); | 139 | str->rg_flags = cpu_to_be32(rg->rg_flags); |
139 | str->rg_free = cpu_to_be32(rg->rg_free); | 140 | str->rg_free = cpu_to_be32(rg->rg_free); |
140 | str->rg_dinodes = cpu_to_be32(rg->rg_dinodes); | 141 | str->rg_dinodes = cpu_to_be32(rg->rg_dinodes); |
141 | 142 | str->__pad = cpu_to_be32(0); | |
143 | str->rg_igeneration = cpu_to_be64(rg->rg_igeneration); | ||
142 | memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); | 144 | memset(&str->rg_reserved, 0, sizeof(str->rg_reserved)); |
143 | } | 145 | } |
144 | 146 | ||
@@ -172,6 +174,7 @@ void gfs2_dinode_in(struct gfs2_dinode *di, char *buf) | |||
172 | 174 | ||
173 | di->di_goal_meta = be64_to_cpu(str->di_goal_meta); | 175 | di->di_goal_meta = be64_to_cpu(str->di_goal_meta); |
174 | di->di_goal_data = be64_to_cpu(str->di_goal_data); | 176 | di->di_goal_data = be64_to_cpu(str->di_goal_data); |
177 | di->di_generation = be64_to_cpu(str->di_generation); | ||
175 | 178 | ||
176 | di->di_flags = be32_to_cpu(str->di_flags); | 179 | di->di_flags = be32_to_cpu(str->di_flags); |
177 | di->di_payload_format = be32_to_cpu(str->di_payload_format); | 180 | di->di_payload_format = be32_to_cpu(str->di_payload_format); |
@@ -205,6 +208,7 @@ void gfs2_dinode_out(struct gfs2_dinode *di, char *buf) | |||
205 | 208 | ||
206 | str->di_goal_meta = cpu_to_be64(di->di_goal_meta); | 209 | str->di_goal_meta = cpu_to_be64(di->di_goal_meta); |
207 | str->di_goal_data = cpu_to_be64(di->di_goal_data); | 210 | str->di_goal_data = cpu_to_be64(di->di_goal_data); |
211 | str->di_generation = cpu_to_be64(di->di_generation); | ||
208 | 212 | ||
209 | str->di_flags = cpu_to_be32(di->di_flags); | 213 | str->di_flags = cpu_to_be32(di->di_flags); |
210 | str->di_payload_format = cpu_to_be32(di->di_payload_format); | 214 | str->di_payload_format = cpu_to_be32(di->di_payload_format); |
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 2c4ec5cf21ff..031270ad55e2 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "rgrp.h" | 33 | #include "rgrp.h" |
34 | #include "ops_file.h" | 34 | #include "ops_file.h" |
35 | #include "util.h" | 35 | #include "util.h" |
36 | #include "glops.h" | ||
36 | 37 | ||
37 | /** | 38 | /** |
38 | * gfs2_get_block - Fills in a buffer head with details about a block | 39 | * gfs2_get_block - Fills in a buffer head with details about a block |
@@ -659,6 +660,115 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, | |||
659 | return ret; | 660 | return ret; |
660 | } | 661 | } |
661 | 662 | ||
663 | /** | ||
664 | * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. | ||
665 | * @bh: the buffer we're stuck on | ||
666 | * | ||
667 | */ | ||
668 | |||
669 | static void stuck_releasepage(struct buffer_head *bh) | ||
670 | { | ||
671 | struct inode *inode = bh->b_page->mapping->host; | ||
672 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | ||
673 | struct gfs2_bufdata *bd = bh->b_private; | ||
674 | struct gfs2_glock *gl; | ||
675 | |||
676 | fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode); | ||
677 | fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", | ||
678 | (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count)); | ||
679 | fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); | ||
680 | fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL"); | ||
681 | |||
682 | if (!bd) | ||
683 | return; | ||
684 | |||
685 | gl = bd->bd_gl; | ||
686 | |||
687 | fs_warn(sdp, "gl = (%u, %llu)\n", | ||
688 | gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number); | ||
689 | |||
690 | fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", | ||
691 | (list_empty(&bd->bd_list_tr)) ? "no" : "yes", | ||
692 | (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); | ||
693 | |||
694 | if (gl->gl_ops == &gfs2_inode_glops) { | ||
695 | struct gfs2_inode *ip = gl->gl_object; | ||
696 | unsigned int x; | ||
697 | |||
698 | if (!ip) | ||
699 | return; | ||
700 | |||
701 | fs_warn(sdp, "ip = %llu %llu\n", | ||
702 | (unsigned long long)ip->i_num.no_formal_ino, | ||
703 | (unsigned long long)ip->i_num.no_addr); | ||
704 | |||
705 | for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) | ||
706 | fs_warn(sdp, "ip->i_cache[%u] = %s\n", | ||
707 | x, (ip->i_cache[x]) ? "!NULL" : "NULL"); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | /** | ||
712 | * gfs2_aspace_releasepage - free the metadata associated with a page | ||
713 | * @page: the page that's being released | ||
714 | * @gfp_mask: passed from Linux VFS, ignored by us | ||
715 | * | ||
716 | * Call try_to_free_buffers() if the buffers in this page can be | ||
717 | * released. | ||
718 | * | ||
719 | * Returns: 0 | ||
720 | */ | ||
721 | |||
722 | int gfs2_releasepage(struct page *page, gfp_t gfp_mask) | ||
723 | { | ||
724 | struct inode *aspace = page->mapping->host; | ||
725 | struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info; | ||
726 | struct buffer_head *bh, *head; | ||
727 | struct gfs2_bufdata *bd; | ||
728 | unsigned long t; | ||
729 | |||
730 | if (!page_has_buffers(page)) | ||
731 | goto out; | ||
732 | |||
733 | head = bh = page_buffers(page); | ||
734 | do { | ||
735 | t = jiffies; | ||
736 | |||
737 | while (atomic_read(&bh->b_count)) { | ||
738 | if (atomic_read(&aspace->i_writecount)) { | ||
739 | if (time_after_eq(jiffies, t + | ||
740 | gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { | ||
741 | stuck_releasepage(bh); | ||
742 | t = jiffies; | ||
743 | } | ||
744 | |||
745 | yield(); | ||
746 | continue; | ||
747 | } | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | gfs2_assert_warn(sdp, !buffer_pinned(bh)); | ||
753 | |||
754 | bd = bh->b_private; | ||
755 | if (bd) { | ||
756 | gfs2_assert_warn(sdp, bd->bd_bh == bh); | ||
757 | gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); | ||
758 | gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); | ||
759 | gfs2_assert_warn(sdp, !bd->bd_ail); | ||
760 | kmem_cache_free(gfs2_bufdata_cachep, bd); | ||
761 | bh->b_private = NULL; | ||
762 | } | ||
763 | |||
764 | bh = bh->b_this_page; | ||
765 | } | ||
766 | while (bh != head); | ||
767 | |||
768 | out: | ||
769 | return try_to_free_buffers(page); | ||
770 | } | ||
771 | |||
662 | const struct address_space_operations gfs2_file_aops = { | 772 | const struct address_space_operations gfs2_file_aops = { |
663 | .writepage = gfs2_writepage, | 773 | .writepage = gfs2_writepage, |
664 | .readpage = gfs2_readpage, | 774 | .readpage = gfs2_readpage, |
@@ -668,6 +778,7 @@ const struct address_space_operations gfs2_file_aops = { | |||
668 | .commit_write = gfs2_commit_write, | 778 | .commit_write = gfs2_commit_write, |
669 | .bmap = gfs2_bmap, | 779 | .bmap = gfs2_bmap, |
670 | .invalidatepage = gfs2_invalidatepage, | 780 | .invalidatepage = gfs2_invalidatepage, |
781 | .releasepage = gfs2_releasepage, | ||
671 | .direct_IO = gfs2_direct_IO, | 782 | .direct_IO = gfs2_direct_IO, |
672 | }; | 783 | }; |
673 | 784 | ||
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index a7ef3bf36f3e..dfc3dda6de11 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h | |||
@@ -13,5 +13,6 @@ | |||
13 | extern const struct address_space_operations gfs2_file_aops; | 13 | extern const struct address_space_operations gfs2_file_aops; |
14 | extern int gfs2_get_block(struct inode *inode, sector_t lblock, | 14 | extern int gfs2_get_block(struct inode *inode, sector_t lblock, |
15 | struct buffer_head *bh_result, int create); | 15 | struct buffer_head *bh_result, int create); |
16 | extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask); | ||
16 | 17 | ||
17 | #endif /* __OPS_ADDRESS_DOT_H__ */ | 18 | #endif /* __OPS_ADDRESS_DOT_H__ */ |
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index c8e2c98700a7..26f1d3249b0f 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -333,7 +333,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, | |||
333 | int error; | 333 | int error; |
334 | 334 | ||
335 | error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset, | 335 | error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset, |
336 | inum->no_formal_ino, type); | 336 | inum->no_addr, type); |
337 | if (error) | 337 | if (error) |
338 | return 1; | 338 | return 1; |
339 | 339 | ||
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 14c1f88bfb5d..65eea0b88bf7 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -1205,7 +1205,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, uint64_t bstart, | |||
1205 | * Returns: the allocated block | 1205 | * Returns: the allocated block |
1206 | */ | 1206 | */ |
1207 | 1207 | ||
1208 | uint64_t gfs2_alloc_data(struct gfs2_inode *ip) | 1208 | u64 gfs2_alloc_data(struct gfs2_inode *ip) |
1209 | { | 1209 | { |
1210 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1210 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1211 | struct gfs2_alloc *al = &ip->i_alloc; | 1211 | struct gfs2_alloc *al = &ip->i_alloc; |
@@ -1249,7 +1249,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip) | |||
1249 | * Returns: the allocated block | 1249 | * Returns: the allocated block |
1250 | */ | 1250 | */ |
1251 | 1251 | ||
1252 | uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) | 1252 | u64 gfs2_alloc_meta(struct gfs2_inode *ip) |
1253 | { | 1253 | { |
1254 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1254 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1255 | struct gfs2_alloc *al = &ip->i_alloc; | 1255 | struct gfs2_alloc *al = &ip->i_alloc; |
@@ -1294,13 +1294,13 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) | |||
1294 | * Returns: the block allocated | 1294 | * Returns: the block allocated |
1295 | */ | 1295 | */ |
1296 | 1296 | ||
1297 | uint64_t gfs2_alloc_di(struct gfs2_inode *dip) | 1297 | u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) |
1298 | { | 1298 | { |
1299 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 1299 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
1300 | struct gfs2_alloc *al = &dip->i_alloc; | 1300 | struct gfs2_alloc *al = &dip->i_alloc; |
1301 | struct gfs2_rgrpd *rgd = al->al_rgd; | 1301 | struct gfs2_rgrpd *rgd = al->al_rgd; |
1302 | uint32_t blk; | 1302 | u32 blk; |
1303 | uint64_t block; | 1303 | u64 block; |
1304 | 1304 | ||
1305 | blk = rgblk_search(rgd, rgd->rd_last_alloc_meta, | 1305 | blk = rgblk_search(rgd, rgd->rd_last_alloc_meta, |
1306 | GFS2_BLKST_FREE, GFS2_BLKST_DINODE); | 1306 | GFS2_BLKST_FREE, GFS2_BLKST_DINODE); |
@@ -1312,7 +1312,7 @@ uint64_t gfs2_alloc_di(struct gfs2_inode *dip) | |||
1312 | gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); | 1312 | gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); |
1313 | rgd->rd_rg.rg_free--; | 1313 | rgd->rd_rg.rg_free--; |
1314 | rgd->rd_rg.rg_dinodes++; | 1314 | rgd->rd_rg.rg_dinodes++; |
1315 | 1315 | *generation = rgd->rd_rg.rg_igeneration++; | |
1316 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); | 1316 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); |
1317 | gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); | 1317 | gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); |
1318 | 1318 | ||
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 9c42d2252ddd..14600944d184 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h | |||
@@ -37,9 +37,9 @@ void gfs2_inplace_release(struct gfs2_inode *ip); | |||
37 | 37 | ||
38 | unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block); | 38 | unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, uint64_t block); |
39 | 39 | ||
40 | uint64_t gfs2_alloc_data(struct gfs2_inode *ip); | 40 | u64 gfs2_alloc_data(struct gfs2_inode *ip); |
41 | uint64_t gfs2_alloc_meta(struct gfs2_inode *ip); | 41 | u64 gfs2_alloc_meta(struct gfs2_inode *ip); |
42 | uint64_t gfs2_alloc_di(struct gfs2_inode *ip); | 42 | u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation); |
43 | 43 | ||
44 | void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); | 44 | void gfs2_free_data(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); |
45 | void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); | 45 | void gfs2_free_meta(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen); |
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 1181da831939..3ebd8743ce8c 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h | |||
@@ -170,8 +170,10 @@ struct gfs2_rgrp { | |||
170 | __be32 rg_flags; | 170 | __be32 rg_flags; |
171 | __be32 rg_free; | 171 | __be32 rg_free; |
172 | __be32 rg_dinodes; | 172 | __be32 rg_dinodes; |
173 | __be32 __pad; | ||
174 | __be64 rg_igeneration; | ||
173 | 175 | ||
174 | __u8 rg_reserved[92]; /* Several fields from gfs1 now reserved */ | 176 | __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */ |
175 | }; | 177 | }; |
176 | 178 | ||
177 | /* | 179 | /* |
@@ -248,7 +250,7 @@ struct gfs2_dinode { | |||
248 | */ | 250 | */ |
249 | __be64 di_goal_meta; /* rgrp to alloc from next */ | 251 | __be64 di_goal_meta; /* rgrp to alloc from next */ |
250 | __be64 di_goal_data; /* data block goal */ | 252 | __be64 di_goal_data; /* data block goal */ |
251 | __u32 __pad[2]; | 253 | __be64 di_generation; /* generation number for NFS */ |
252 | 254 | ||
253 | __be32 di_flags; /* GFS2_DIF_... */ | 255 | __be32 di_flags; /* GFS2_DIF_... */ |
254 | __be32 di_payload_format; /* GFS2_FORMAT_... */ | 256 | __be32 di_payload_format; /* GFS2_FORMAT_... */ |