.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
---|
3 | 4 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
---|
4 | | - * |
---|
5 | | - * This copyrighted material is made available to anyone wishing to use, |
---|
6 | | - * modify, copy, or redistribute it subject to the terms and conditions |
---|
7 | | - * of the GNU General Public License version 2. |
---|
8 | 5 | */ |
---|
9 | 6 | |
---|
10 | 7 | #include <linux/spinlock.h> |
---|
.. | .. |
---|
14 | 11 | #include <linux/gfs2_ondisk.h> |
---|
15 | 12 | #include <linux/crc32.h> |
---|
16 | 13 | #include <linux/iomap.h> |
---|
| 14 | +#include <linux/ktime.h> |
---|
17 | 15 | |
---|
18 | 16 | #include "gfs2.h" |
---|
19 | 17 | #include "incore.h" |
---|
.. | .. |
---|
58 | 56 | u64 block, struct page *page) |
---|
59 | 57 | { |
---|
60 | 58 | struct inode *inode = &ip->i_inode; |
---|
61 | | - struct buffer_head *bh; |
---|
62 | 59 | int release = 0; |
---|
63 | 60 | |
---|
64 | 61 | if (!page || page->index) { |
---|
.. | .. |
---|
72 | 69 | void *kaddr = kmap(page); |
---|
73 | 70 | u64 dsize = i_size_read(inode); |
---|
74 | 71 | |
---|
75 | | - if (dsize > gfs2_max_stuffed_size(ip)) |
---|
76 | | - dsize = gfs2_max_stuffed_size(ip); |
---|
77 | | - |
---|
78 | 72 | memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize); |
---|
79 | 73 | memset(kaddr + dsize, 0, PAGE_SIZE - dsize); |
---|
80 | 74 | kunmap(page); |
---|
.. | .. |
---|
82 | 76 | SetPageUptodate(page); |
---|
83 | 77 | } |
---|
84 | 78 | |
---|
85 | | - if (!page_has_buffers(page)) |
---|
86 | | - create_empty_buffers(page, BIT(inode->i_blkbits), |
---|
87 | | - BIT(BH_Uptodate)); |
---|
| 79 | + if (gfs2_is_jdata(ip)) { |
---|
| 80 | + struct buffer_head *bh; |
---|
88 | 81 | |
---|
89 | | - bh = page_buffers(page); |
---|
| 82 | + if (!page_has_buffers(page)) |
---|
| 83 | + create_empty_buffers(page, BIT(inode->i_blkbits), |
---|
| 84 | + BIT(BH_Uptodate)); |
---|
90 | 85 | |
---|
91 | | - if (!buffer_mapped(bh)) |
---|
92 | | - map_bh(bh, inode->i_sb, block); |
---|
| 86 | + bh = page_buffers(page); |
---|
| 87 | + if (!buffer_mapped(bh)) |
---|
| 88 | + map_bh(bh, inode->i_sb, block); |
---|
93 | 89 | |
---|
94 | | - set_buffer_uptodate(bh); |
---|
95 | | - if (gfs2_is_jdata(ip)) |
---|
| 90 | + set_buffer_uptodate(bh); |
---|
96 | 91 | gfs2_trans_add_data(ip->i_gl, bh); |
---|
97 | | - else { |
---|
98 | | - mark_buffer_dirty(bh); |
---|
| 92 | + } else { |
---|
| 93 | + set_page_dirty(page); |
---|
99 | 94 | gfs2_ordered_add_inode(ip); |
---|
100 | 95 | } |
---|
101 | 96 | |
---|
.. | .. |
---|
141 | 136 | if (error) |
---|
142 | 137 | goto out_brelse; |
---|
143 | 138 | if (isdir) { |
---|
144 | | - gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1); |
---|
| 139 | + gfs2_trans_remove_revoke(GFS2_SB(&ip->i_inode), block, 1); |
---|
145 | 140 | error = gfs2_dir_get_new_buffer(ip, block, &bh); |
---|
146 | 141 | if (error) |
---|
147 | 142 | goto out_brelse; |
---|
.. | .. |
---|
637 | 632 | * gfs2_iomap_alloc - Build a metadata tree of the requested height |
---|
638 | 633 | * @inode: The GFS2 inode |
---|
639 | 634 | * @iomap: The iomap structure |
---|
640 | | - * @flags: iomap flags |
---|
641 | 635 | * @mp: The metapath, with proper height information calculated |
---|
642 | 636 | * |
---|
643 | 637 | * In this routine we may have to alloc: |
---|
.. | .. |
---|
664 | 658 | */ |
---|
665 | 659 | |
---|
666 | 660 | static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, |
---|
667 | | - unsigned flags, struct metapath *mp) |
---|
| 661 | + struct metapath *mp) |
---|
668 | 662 | { |
---|
669 | 663 | struct gfs2_inode *ip = GFS2_I(inode); |
---|
670 | 664 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
---|
.. | .. |
---|
715 | 709 | goto out; |
---|
716 | 710 | alloced += n; |
---|
717 | 711 | if (state != ALLOC_DATA || gfs2_is_jdata(ip)) |
---|
718 | | - gfs2_trans_add_unrevoke(sdp, bn, n); |
---|
| 712 | + gfs2_trans_remove_revoke(sdp, bn, n); |
---|
719 | 713 | switch (state) { |
---|
720 | 714 | /* Growing height of tree */ |
---|
721 | 715 | case ALLOC_GROW_HEIGHT: |
---|
.. | .. |
---|
749 | 743 | } |
---|
750 | 744 | if (n == 0) |
---|
751 | 745 | break; |
---|
752 | | - /* Branching from existing tree */ |
---|
| 746 | + fallthrough; /* To branching from existing tree */ |
---|
753 | 747 | case ALLOC_GROW_DEPTH: |
---|
754 | 748 | if (i > 1 && i < mp->mp_fheight) |
---|
755 | 749 | gfs2_trans_add_meta(ip->i_gl, mp->mp_bh[i-1]); |
---|
.. | .. |
---|
760 | 754 | state = ALLOC_DATA; |
---|
761 | 755 | if (n == 0) |
---|
762 | 756 | break; |
---|
763 | | - /* Tree complete, adding data blocks */ |
---|
| 757 | + fallthrough; /* To tree complete, adding data blocks */ |
---|
764 | 758 | case ALLOC_DATA: |
---|
765 | 759 | BUG_ON(n > dblks); |
---|
766 | 760 | BUG_ON(mp->mp_bh[end_of_metadata] == NULL); |
---|
.. | .. |
---|
964 | 958 | goto out; |
---|
965 | 959 | } |
---|
966 | 960 | |
---|
| 961 | +/** |
---|
| 962 | + * gfs2_lblk_to_dblk - convert logical block to disk block |
---|
| 963 | + * @inode: the inode of the file we're mapping |
---|
| 964 | + * @lblock: the block relative to the start of the file |
---|
| 965 | + * @dblock: the returned dblock, if no error |
---|
| 966 | + * |
---|
| 967 | + * This function maps a single block from a file logical block (relative to |
---|
| 968 | + * the start of the file) to a file system absolute block using iomap. |
---|
| 969 | + * |
---|
| 970 | + * Returns: the absolute file system block, or an error |
---|
| 971 | + */ |
---|
| 972 | +int gfs2_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock) |
---|
| 973 | +{ |
---|
| 974 | + struct iomap iomap = { }; |
---|
| 975 | + struct metapath mp = { .mp_aheight = 1, }; |
---|
| 976 | + loff_t pos = (loff_t)lblock << inode->i_blkbits; |
---|
| 977 | + int ret; |
---|
| 978 | + |
---|
| 979 | + ret = gfs2_iomap_get(inode, pos, i_blocksize(inode), 0, &iomap, &mp); |
---|
| 980 | + release_metapath(&mp); |
---|
| 981 | + if (ret == 0) |
---|
| 982 | + *dblock = iomap.addr >> inode->i_blkbits; |
---|
| 983 | + |
---|
| 984 | + return ret; |
---|
| 985 | +} |
---|
| 986 | + |
---|
967 | 987 | static int gfs2_write_lock(struct inode *inode) |
---|
968 | 988 | { |
---|
969 | 989 | struct gfs2_inode *ip = GFS2_I(inode); |
---|
.. | .. |
---|
1004 | 1024 | gfs2_glock_dq_uninit(&ip->i_gh); |
---|
1005 | 1025 | } |
---|
1006 | 1026 | |
---|
1007 | | -static void gfs2_iomap_journaled_page_done(struct inode *inode, loff_t pos, |
---|
1008 | | - unsigned copied, struct page *page, |
---|
1009 | | - struct iomap *iomap) |
---|
| 1027 | +static int gfs2_iomap_page_prepare(struct inode *inode, loff_t pos, |
---|
| 1028 | + unsigned len, struct iomap *iomap) |
---|
1010 | 1029 | { |
---|
1011 | | - struct gfs2_inode *ip = GFS2_I(inode); |
---|
| 1030 | + unsigned int blockmask = i_blocksize(inode) - 1; |
---|
| 1031 | + struct gfs2_sbd *sdp = GFS2_SB(inode); |
---|
| 1032 | + unsigned int blocks; |
---|
1012 | 1033 | |
---|
1013 | | - gfs2_page_add_databufs(ip, page, offset_in_page(pos), copied); |
---|
| 1034 | + blocks = ((pos & blockmask) + len + blockmask) >> inode->i_blkbits; |
---|
| 1035 | + return gfs2_trans_begin(sdp, RES_DINODE + blocks, 0); |
---|
1014 | 1036 | } |
---|
| 1037 | + |
---|
| 1038 | +static void gfs2_iomap_page_done(struct inode *inode, loff_t pos, |
---|
| 1039 | + unsigned copied, struct page *page, |
---|
| 1040 | + struct iomap *iomap) |
---|
| 1041 | +{ |
---|
| 1042 | + struct gfs2_trans *tr = current->journal_info; |
---|
| 1043 | + struct gfs2_inode *ip = GFS2_I(inode); |
---|
| 1044 | + struct gfs2_sbd *sdp = GFS2_SB(inode); |
---|
| 1045 | + |
---|
| 1046 | + if (page && !gfs2_is_stuffed(ip)) |
---|
| 1047 | + gfs2_page_add_databufs(ip, page, offset_in_page(pos), copied); |
---|
| 1048 | + |
---|
| 1049 | + if (tr->tr_num_buf_new) |
---|
| 1050 | + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
---|
| 1051 | + |
---|
| 1052 | + gfs2_trans_end(sdp); |
---|
| 1053 | +} |
---|
| 1054 | + |
---|
| 1055 | +static const struct iomap_page_ops gfs2_iomap_page_ops = { |
---|
| 1056 | + .page_prepare = gfs2_iomap_page_prepare, |
---|
| 1057 | + .page_done = gfs2_iomap_page_done, |
---|
| 1058 | +}; |
---|
1015 | 1059 | |
---|
1016 | 1060 | static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, |
---|
1017 | 1061 | loff_t length, unsigned flags, |
---|
.. | .. |
---|
1020 | 1064 | { |
---|
1021 | 1065 | struct gfs2_inode *ip = GFS2_I(inode); |
---|
1022 | 1066 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
---|
1023 | | - unsigned int data_blocks = 0, ind_blocks = 0, rblocks; |
---|
1024 | | - bool unstuff, alloc_required; |
---|
| 1067 | + bool unstuff; |
---|
1025 | 1068 | int ret; |
---|
1026 | | - |
---|
1027 | | - ret = gfs2_write_lock(inode); |
---|
1028 | | - if (ret) |
---|
1029 | | - return ret; |
---|
1030 | 1069 | |
---|
1031 | 1070 | unstuff = gfs2_is_stuffed(ip) && |
---|
1032 | 1071 | pos + length > gfs2_max_stuffed_size(ip); |
---|
1033 | 1072 | |
---|
1034 | | - ret = gfs2_iomap_get(inode, pos, length, flags, iomap, mp); |
---|
1035 | | - if (ret) |
---|
1036 | | - goto out_unlock; |
---|
| 1073 | + if (unstuff || iomap->type == IOMAP_HOLE) { |
---|
| 1074 | + unsigned int data_blocks, ind_blocks; |
---|
| 1075 | + struct gfs2_alloc_parms ap = {}; |
---|
| 1076 | + unsigned int rblocks; |
---|
| 1077 | + struct gfs2_trans *tr; |
---|
1037 | 1078 | |
---|
1038 | | - alloc_required = unstuff || iomap->type == IOMAP_HOLE; |
---|
1039 | | - |
---|
1040 | | - if (alloc_required || gfs2_is_jdata(ip)) |
---|
1041 | 1079 | gfs2_write_calc_reserv(ip, iomap->length, &data_blocks, |
---|
1042 | 1080 | &ind_blocks); |
---|
1043 | | - |
---|
1044 | | - if (alloc_required) { |
---|
1045 | | - struct gfs2_alloc_parms ap = { |
---|
1046 | | - .target = data_blocks + ind_blocks |
---|
1047 | | - }; |
---|
1048 | | - |
---|
| 1081 | + ap.target = data_blocks + ind_blocks; |
---|
1049 | 1082 | ret = gfs2_quota_lock_check(ip, &ap); |
---|
1050 | 1083 | if (ret) |
---|
1051 | | - goto out_unlock; |
---|
| 1084 | + return ret; |
---|
1052 | 1085 | |
---|
1053 | 1086 | ret = gfs2_inplace_reserve(ip, &ap); |
---|
1054 | 1087 | if (ret) |
---|
1055 | 1088 | goto out_qunlock; |
---|
1056 | | - } |
---|
1057 | 1089 | |
---|
1058 | | - rblocks = RES_DINODE + ind_blocks; |
---|
1059 | | - if (gfs2_is_jdata(ip)) |
---|
1060 | | - rblocks += data_blocks; |
---|
1061 | | - if (ind_blocks || data_blocks) |
---|
1062 | | - rblocks += RES_STATFS + RES_QUOTA; |
---|
1063 | | - if (inode == sdp->sd_rindex) |
---|
1064 | | - rblocks += 2 * RES_STATFS; |
---|
1065 | | - if (alloc_required) |
---|
| 1090 | + rblocks = RES_DINODE + ind_blocks; |
---|
| 1091 | + if (gfs2_is_jdata(ip)) |
---|
| 1092 | + rblocks += data_blocks; |
---|
| 1093 | + if (ind_blocks || data_blocks) |
---|
| 1094 | + rblocks += RES_STATFS + RES_QUOTA; |
---|
| 1095 | + if (inode == sdp->sd_rindex) |
---|
| 1096 | + rblocks += 2 * RES_STATFS; |
---|
1066 | 1097 | rblocks += gfs2_rg_blocks(ip, data_blocks + ind_blocks); |
---|
1067 | 1098 | |
---|
1068 | | - ret = gfs2_trans_begin(sdp, rblocks, iomap->length >> inode->i_blkbits); |
---|
1069 | | - if (ret) |
---|
1070 | | - goto out_trans_fail; |
---|
1071 | | - |
---|
1072 | | - if (unstuff) { |
---|
1073 | | - ret = gfs2_unstuff_dinode(ip, NULL); |
---|
| 1099 | + ret = gfs2_trans_begin(sdp, rblocks, |
---|
| 1100 | + iomap->length >> inode->i_blkbits); |
---|
1074 | 1101 | if (ret) |
---|
1075 | | - goto out_trans_end; |
---|
1076 | | - release_metapath(mp); |
---|
1077 | | - ret = gfs2_iomap_get(inode, iomap->offset, iomap->length, |
---|
1078 | | - flags, iomap, mp); |
---|
1079 | | - if (ret) |
---|
1080 | | - goto out_trans_end; |
---|
1081 | | - } |
---|
| 1102 | + goto out_trans_fail; |
---|
1082 | 1103 | |
---|
1083 | | - if (iomap->type == IOMAP_HOLE) { |
---|
1084 | | - ret = gfs2_iomap_alloc(inode, iomap, flags, mp); |
---|
1085 | | - if (ret) { |
---|
1086 | | - gfs2_trans_end(sdp); |
---|
1087 | | - gfs2_inplace_release(ip); |
---|
1088 | | - punch_hole(ip, iomap->offset, iomap->length); |
---|
1089 | | - goto out_qunlock; |
---|
| 1104 | + if (unstuff) { |
---|
| 1105 | + ret = gfs2_unstuff_dinode(ip, NULL); |
---|
| 1106 | + if (ret) |
---|
| 1107 | + goto out_trans_end; |
---|
| 1108 | + release_metapath(mp); |
---|
| 1109 | + ret = gfs2_iomap_get(inode, iomap->offset, |
---|
| 1110 | + iomap->length, flags, iomap, mp); |
---|
| 1111 | + if (ret) |
---|
| 1112 | + goto out_trans_end; |
---|
1090 | 1113 | } |
---|
| 1114 | + |
---|
| 1115 | + if (iomap->type == IOMAP_HOLE) { |
---|
| 1116 | + ret = gfs2_iomap_alloc(inode, iomap, mp); |
---|
| 1117 | + if (ret) { |
---|
| 1118 | + gfs2_trans_end(sdp); |
---|
| 1119 | + gfs2_inplace_release(ip); |
---|
| 1120 | + punch_hole(ip, iomap->offset, iomap->length); |
---|
| 1121 | + goto out_qunlock; |
---|
| 1122 | + } |
---|
| 1123 | + } |
---|
| 1124 | + |
---|
| 1125 | + tr = current->journal_info; |
---|
| 1126 | + if (tr->tr_num_buf_new) |
---|
| 1127 | + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
---|
| 1128 | + |
---|
| 1129 | + gfs2_trans_end(sdp); |
---|
1091 | 1130 | } |
---|
1092 | | - if (!gfs2_is_stuffed(ip) && gfs2_is_jdata(ip)) |
---|
1093 | | - iomap->page_done = gfs2_iomap_journaled_page_done; |
---|
| 1131 | + |
---|
| 1132 | + if (gfs2_is_stuffed(ip) || gfs2_is_jdata(ip)) |
---|
| 1133 | + iomap->page_ops = &gfs2_iomap_page_ops; |
---|
1094 | 1134 | return 0; |
---|
1095 | 1135 | |
---|
1096 | 1136 | out_trans_end: |
---|
1097 | 1137 | gfs2_trans_end(sdp); |
---|
1098 | 1138 | out_trans_fail: |
---|
1099 | | - if (alloc_required) |
---|
1100 | | - gfs2_inplace_release(ip); |
---|
| 1139 | + gfs2_inplace_release(ip); |
---|
1101 | 1140 | out_qunlock: |
---|
1102 | | - if (alloc_required) |
---|
1103 | | - gfs2_quota_unlock(ip); |
---|
1104 | | -out_unlock: |
---|
1105 | | - gfs2_write_unlock(inode); |
---|
| 1141 | + gfs2_quota_unlock(ip); |
---|
1106 | 1142 | return ret; |
---|
1107 | 1143 | } |
---|
1108 | 1144 | |
---|
| 1145 | +static inline bool gfs2_iomap_need_write_lock(unsigned flags) |
---|
| 1146 | +{ |
---|
| 1147 | + return (flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT); |
---|
| 1148 | +} |
---|
| 1149 | + |
---|
1109 | 1150 | static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, |
---|
1110 | | - unsigned flags, struct iomap *iomap) |
---|
| 1151 | + unsigned flags, struct iomap *iomap, |
---|
| 1152 | + struct iomap *srcmap) |
---|
1111 | 1153 | { |
---|
1112 | 1154 | struct gfs2_inode *ip = GFS2_I(inode); |
---|
1113 | 1155 | struct metapath mp = { .mp_aheight = 1, }; |
---|
1114 | 1156 | int ret; |
---|
1115 | 1157 | |
---|
1116 | | - iomap->flags |= IOMAP_F_BUFFER_HEAD; |
---|
| 1158 | + if (gfs2_is_jdata(ip)) |
---|
| 1159 | + iomap->flags |= IOMAP_F_BUFFER_HEAD; |
---|
1117 | 1160 | |
---|
1118 | 1161 | trace_gfs2_iomap_start(ip, pos, length, flags); |
---|
1119 | | - if ((flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT)) { |
---|
1120 | | - ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); |
---|
1121 | | - } else { |
---|
1122 | | - ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); |
---|
| 1162 | + if (gfs2_iomap_need_write_lock(flags)) { |
---|
| 1163 | + ret = gfs2_write_lock(inode); |
---|
| 1164 | + if (ret) |
---|
| 1165 | + goto out; |
---|
| 1166 | + } |
---|
1123 | 1167 | |
---|
1124 | | - /* |
---|
1125 | | - * Silently fall back to buffered I/O for stuffed files or if |
---|
1126 | | - * we've hot a hole (see gfs2_file_direct_write). |
---|
1127 | | - */ |
---|
1128 | | - if ((flags & IOMAP_WRITE) && (flags & IOMAP_DIRECT) && |
---|
1129 | | - iomap->type != IOMAP_MAPPED) |
---|
1130 | | - ret = -ENOTBLK; |
---|
| 1168 | + ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); |
---|
| 1169 | + if (ret) |
---|
| 1170 | + goto out_unlock; |
---|
| 1171 | + |
---|
| 1172 | + switch(flags & (IOMAP_WRITE | IOMAP_ZERO)) { |
---|
| 1173 | + case IOMAP_WRITE: |
---|
| 1174 | + if (flags & IOMAP_DIRECT) { |
---|
| 1175 | + /* |
---|
| 1176 | + * Silently fall back to buffered I/O for stuffed files |
---|
| 1177 | + * or if we've got a hole (see gfs2_file_direct_write). |
---|
| 1178 | + */ |
---|
| 1179 | + if (iomap->type != IOMAP_MAPPED) |
---|
| 1180 | + ret = -ENOTBLK; |
---|
| 1181 | + goto out_unlock; |
---|
| 1182 | + } |
---|
| 1183 | + break; |
---|
| 1184 | + case IOMAP_ZERO: |
---|
| 1185 | + if (iomap->type == IOMAP_HOLE) |
---|
| 1186 | + goto out_unlock; |
---|
| 1187 | + break; |
---|
| 1188 | + default: |
---|
| 1189 | + goto out_unlock; |
---|
1131 | 1190 | } |
---|
1132 | | - if (!ret) { |
---|
1133 | | - get_bh(mp.mp_bh[0]); |
---|
1134 | | - iomap->private = mp.mp_bh[0]; |
---|
1135 | | - } |
---|
| 1191 | + |
---|
| 1192 | + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); |
---|
| 1193 | + |
---|
| 1194 | +out_unlock: |
---|
| 1195 | + if (ret && gfs2_iomap_need_write_lock(flags)) |
---|
| 1196 | + gfs2_write_unlock(inode); |
---|
1136 | 1197 | release_metapath(&mp); |
---|
| 1198 | +out: |
---|
1137 | 1199 | trace_gfs2_iomap_end(ip, iomap, ret); |
---|
1138 | 1200 | return ret; |
---|
1139 | 1201 | } |
---|
.. | .. |
---|
1143 | 1205 | { |
---|
1144 | 1206 | struct gfs2_inode *ip = GFS2_I(inode); |
---|
1145 | 1207 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
---|
1146 | | - struct gfs2_trans *tr = current->journal_info; |
---|
1147 | | - struct buffer_head *dibh = iomap->private; |
---|
1148 | 1208 | |
---|
1149 | | - if ((flags & (IOMAP_WRITE | IOMAP_DIRECT)) != IOMAP_WRITE) |
---|
1150 | | - goto out; |
---|
| 1209 | + switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) { |
---|
| 1210 | + case IOMAP_WRITE: |
---|
| 1211 | + if (flags & IOMAP_DIRECT) |
---|
| 1212 | + return 0; |
---|
| 1213 | + break; |
---|
| 1214 | + case IOMAP_ZERO: |
---|
| 1215 | + if (iomap->type == IOMAP_HOLE) |
---|
| 1216 | + return 0; |
---|
| 1217 | + break; |
---|
| 1218 | + default: |
---|
| 1219 | + return 0; |
---|
| 1220 | + } |
---|
1151 | 1221 | |
---|
1152 | | - if (iomap->type != IOMAP_INLINE) { |
---|
| 1222 | + if (!gfs2_is_stuffed(ip)) |
---|
1153 | 1223 | gfs2_ordered_add_inode(ip); |
---|
1154 | 1224 | |
---|
1155 | | - if (tr->tr_num_buf_new) |
---|
1156 | | - __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
---|
1157 | | - else |
---|
1158 | | - gfs2_trans_add_meta(ip->i_gl, dibh); |
---|
1159 | | - } |
---|
1160 | | - |
---|
1161 | | - if (inode == sdp->sd_rindex) { |
---|
| 1225 | + if (inode == sdp->sd_rindex) |
---|
1162 | 1226 | adjust_fs_space(inode); |
---|
1163 | | - sdp->sd_rindex_uptodate = 0; |
---|
1164 | | - } |
---|
1165 | 1227 | |
---|
1166 | | - gfs2_trans_end(sdp); |
---|
1167 | 1228 | gfs2_inplace_release(ip); |
---|
1168 | | - |
---|
1169 | | - if (length != written && (iomap->flags & IOMAP_F_NEW)) { |
---|
1170 | | - /* Deallocate blocks that were just allocated. */ |
---|
1171 | | - loff_t blockmask = i_blocksize(inode) - 1; |
---|
1172 | | - loff_t end = (pos + length) & ~blockmask; |
---|
1173 | | - |
---|
1174 | | - pos = (pos + written + blockmask) & ~blockmask; |
---|
1175 | | - if (pos < end) { |
---|
1176 | | - truncate_pagecache_range(inode, pos, end - 1); |
---|
1177 | | - punch_hole(ip, pos, end - pos); |
---|
1178 | | - } |
---|
1179 | | - } |
---|
1180 | 1229 | |
---|
1181 | 1230 | if (ip->i_qadata && ip->i_qadata->qa_qd_num) |
---|
1182 | 1231 | gfs2_quota_unlock(ip); |
---|
1183 | | - gfs2_write_unlock(inode); |
---|
1184 | 1232 | |
---|
1185 | | -out: |
---|
1186 | | - if (dibh) |
---|
1187 | | - brelse(dibh); |
---|
| 1233 | + if (length != written && (iomap->flags & IOMAP_F_NEW)) { |
---|
| 1234 | + /* Deallocate blocks that were just allocated. */ |
---|
| 1235 | + loff_t hstart = round_up(pos + written, i_blocksize(inode)); |
---|
| 1236 | + loff_t hend = iomap->offset + iomap->length; |
---|
| 1237 | + |
---|
| 1238 | + if (hstart < hend) { |
---|
| 1239 | + truncate_pagecache_range(inode, hstart, hend - 1); |
---|
| 1240 | + punch_hole(ip, hstart, hend - hstart); |
---|
| 1241 | + } |
---|
| 1242 | + } |
---|
| 1243 | + |
---|
| 1244 | + if (unlikely(!written)) |
---|
| 1245 | + goto out_unlock; |
---|
| 1246 | + |
---|
| 1247 | + if (iomap->flags & IOMAP_F_SIZE_CHANGED) |
---|
| 1248 | + mark_inode_dirty(inode); |
---|
| 1249 | + set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); |
---|
| 1250 | + |
---|
| 1251 | +out_unlock: |
---|
| 1252 | + if (gfs2_iomap_need_write_lock(flags)) |
---|
| 1253 | + gfs2_write_unlock(inode); |
---|
1188 | 1254 | return 0; |
---|
1189 | 1255 | } |
---|
1190 | 1256 | |
---|
.. | .. |
---|
1222 | 1288 | loff_t length = bh_map->b_size; |
---|
1223 | 1289 | struct metapath mp = { .mp_aheight = 1, }; |
---|
1224 | 1290 | struct iomap iomap = { }; |
---|
| 1291 | + int flags = create ? IOMAP_WRITE : 0; |
---|
1225 | 1292 | int ret; |
---|
1226 | 1293 | |
---|
1227 | 1294 | clear_buffer_mapped(bh_map); |
---|
.. | .. |
---|
1229 | 1296 | clear_buffer_boundary(bh_map); |
---|
1230 | 1297 | trace_gfs2_bmap(ip, bh_map, lblock, create, 1); |
---|
1231 | 1298 | |
---|
1232 | | - if (create) { |
---|
1233 | | - ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, &iomap, &mp); |
---|
1234 | | - if (!ret && iomap.type == IOMAP_HOLE) |
---|
1235 | | - ret = gfs2_iomap_alloc(inode, &iomap, IOMAP_WRITE, &mp); |
---|
1236 | | - release_metapath(&mp); |
---|
1237 | | - } else { |
---|
1238 | | - ret = gfs2_iomap_get(inode, pos, length, 0, &iomap, &mp); |
---|
1239 | | - release_metapath(&mp); |
---|
1240 | | - } |
---|
| 1299 | + ret = gfs2_iomap_get(inode, pos, length, flags, &iomap, &mp); |
---|
| 1300 | + if (create && !ret && iomap.type == IOMAP_HOLE) |
---|
| 1301 | + ret = gfs2_iomap_alloc(inode, &iomap, &mp); |
---|
| 1302 | + release_metapath(&mp); |
---|
1241 | 1303 | if (ret) |
---|
1242 | 1304 | goto out; |
---|
1243 | 1305 | |
---|
.. | .. |
---|
1282 | 1344 | return ret; |
---|
1283 | 1345 | } |
---|
1284 | 1346 | |
---|
1285 | | -/** |
---|
1286 | | - * gfs2_block_zero_range - Deal with zeroing out data |
---|
1287 | | - * |
---|
1288 | | - * This is partly borrowed from ext3. |
---|
| 1347 | +/* |
---|
| 1348 | + * NOTE: Never call gfs2_block_zero_range with an open transaction because it |
---|
| 1349 | + * uses iomap write to perform its actions, which begin their own transactions |
---|
| 1350 | + * (iomap_begin, page_prepare, etc.) |
---|
1289 | 1351 | */ |
---|
1290 | 1352 | static int gfs2_block_zero_range(struct inode *inode, loff_t from, |
---|
1291 | 1353 | unsigned int length) |
---|
1292 | 1354 | { |
---|
1293 | | - struct address_space *mapping = inode->i_mapping; |
---|
1294 | | - struct gfs2_inode *ip = GFS2_I(inode); |
---|
1295 | | - unsigned long index = from >> PAGE_SHIFT; |
---|
1296 | | - unsigned offset = from & (PAGE_SIZE-1); |
---|
1297 | | - unsigned blocksize, iblock, pos; |
---|
1298 | | - struct buffer_head *bh; |
---|
1299 | | - struct page *page; |
---|
1300 | | - int err; |
---|
1301 | | - |
---|
1302 | | - page = find_or_create_page(mapping, index, GFP_NOFS); |
---|
1303 | | - if (!page) |
---|
1304 | | - return 0; |
---|
1305 | | - |
---|
1306 | | - blocksize = inode->i_sb->s_blocksize; |
---|
1307 | | - iblock = index << (PAGE_SHIFT - inode->i_sb->s_blocksize_bits); |
---|
1308 | | - |
---|
1309 | | - if (!page_has_buffers(page)) |
---|
1310 | | - create_empty_buffers(page, blocksize, 0); |
---|
1311 | | - |
---|
1312 | | - /* Find the buffer that contains "offset" */ |
---|
1313 | | - bh = page_buffers(page); |
---|
1314 | | - pos = blocksize; |
---|
1315 | | - while (offset >= pos) { |
---|
1316 | | - bh = bh->b_this_page; |
---|
1317 | | - iblock++; |
---|
1318 | | - pos += blocksize; |
---|
1319 | | - } |
---|
1320 | | - |
---|
1321 | | - err = 0; |
---|
1322 | | - |
---|
1323 | | - if (!buffer_mapped(bh)) { |
---|
1324 | | - gfs2_block_map(inode, iblock, bh, 0); |
---|
1325 | | - /* unmapped? It's a hole - nothing to do */ |
---|
1326 | | - if (!buffer_mapped(bh)) |
---|
1327 | | - goto unlock; |
---|
1328 | | - } |
---|
1329 | | - |
---|
1330 | | - /* Ok, it's mapped. Make sure it's up-to-date */ |
---|
1331 | | - if (PageUptodate(page)) |
---|
1332 | | - set_buffer_uptodate(bh); |
---|
1333 | | - |
---|
1334 | | - if (!buffer_uptodate(bh)) { |
---|
1335 | | - err = -EIO; |
---|
1336 | | - ll_rw_block(REQ_OP_READ, 0, 1, &bh); |
---|
1337 | | - wait_on_buffer(bh); |
---|
1338 | | - /* Uhhuh. Read error. Complain and punt. */ |
---|
1339 | | - if (!buffer_uptodate(bh)) |
---|
1340 | | - goto unlock; |
---|
1341 | | - err = 0; |
---|
1342 | | - } |
---|
1343 | | - |
---|
1344 | | - if (gfs2_is_jdata(ip)) |
---|
1345 | | - gfs2_trans_add_data(ip->i_gl, bh); |
---|
1346 | | - else |
---|
1347 | | - gfs2_ordered_add_inode(ip); |
---|
1348 | | - |
---|
1349 | | - zero_user(page, offset, length); |
---|
1350 | | - mark_buffer_dirty(bh); |
---|
1351 | | -unlock: |
---|
1352 | | - unlock_page(page); |
---|
1353 | | - put_page(page); |
---|
1354 | | - return err; |
---|
| 1355 | + BUG_ON(current->journal_info); |
---|
| 1356 | + return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops); |
---|
1355 | 1357 | } |
---|
1356 | 1358 | |
---|
1357 | 1359 | #define GFS2_JTRUNC_REVOKES 8192 |
---|
.. | .. |
---|
1411 | 1413 | u64 oldsize = inode->i_size; |
---|
1412 | 1414 | int error; |
---|
1413 | 1415 | |
---|
| 1416 | + if (!gfs2_is_stuffed(ip)) { |
---|
| 1417 | + unsigned int blocksize = i_blocksize(inode); |
---|
| 1418 | + unsigned int offs = newsize & (blocksize - 1); |
---|
| 1419 | + if (offs) { |
---|
| 1420 | + error = gfs2_block_zero_range(inode, newsize, |
---|
| 1421 | + blocksize - offs); |
---|
| 1422 | + if (error) |
---|
| 1423 | + return error; |
---|
| 1424 | + } |
---|
| 1425 | + } |
---|
1414 | 1426 | if (journaled) |
---|
1415 | 1427 | error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES); |
---|
1416 | 1428 | else |
---|
.. | .. |
---|
1424 | 1436 | |
---|
1425 | 1437 | gfs2_trans_add_meta(ip->i_gl, dibh); |
---|
1426 | 1438 | |
---|
1427 | | - if (gfs2_is_stuffed(ip)) { |
---|
| 1439 | + if (gfs2_is_stuffed(ip)) |
---|
1428 | 1440 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize); |
---|
1429 | | - } else { |
---|
1430 | | - unsigned int blocksize = i_blocksize(inode); |
---|
1431 | | - unsigned int offs = newsize & (blocksize - 1); |
---|
1432 | | - if (offs) { |
---|
1433 | | - error = gfs2_block_zero_range(inode, newsize, |
---|
1434 | | - blocksize - offs); |
---|
1435 | | - if (error) |
---|
1436 | | - goto out; |
---|
1437 | | - } |
---|
| 1441 | + else |
---|
1438 | 1442 | ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; |
---|
1439 | | - } |
---|
1440 | 1443 | |
---|
1441 | 1444 | i_size_write(inode, newsize); |
---|
1442 | 1445 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode); |
---|
.. | .. |
---|
1462 | 1465 | |
---|
1463 | 1466 | ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, iomap, &mp); |
---|
1464 | 1467 | if (!ret && iomap->type == IOMAP_HOLE) |
---|
1465 | | - ret = gfs2_iomap_alloc(inode, iomap, IOMAP_WRITE, &mp); |
---|
| 1468 | + ret = gfs2_iomap_alloc(inode, iomap, &mp); |
---|
1466 | 1469 | release_metapath(&mp); |
---|
1467 | 1470 | return ret; |
---|
1468 | 1471 | } |
---|
.. | .. |
---|
1600 | 1603 | continue; |
---|
1601 | 1604 | } |
---|
1602 | 1605 | if (bstart) { |
---|
1603 | | - __gfs2_free_blocks(ip, bstart, (u32)blen, meta); |
---|
| 1606 | + __gfs2_free_blocks(ip, rgd, bstart, (u32)blen, meta); |
---|
1604 | 1607 | (*btotal) += blen; |
---|
1605 | 1608 | gfs2_add_inode_blocks(&ip->i_inode, -blen); |
---|
1606 | 1609 | } |
---|
.. | .. |
---|
1608 | 1611 | blen = 1; |
---|
1609 | 1612 | } |
---|
1610 | 1613 | if (bstart) { |
---|
1611 | | - __gfs2_free_blocks(ip, bstart, (u32)blen, meta); |
---|
| 1614 | + __gfs2_free_blocks(ip, rgd, bstart, (u32)blen, meta); |
---|
1612 | 1615 | (*btotal) += blen; |
---|
1613 | 1616 | gfs2_add_inode_blocks(&ip->i_inode, -blen); |
---|
1614 | 1617 | } |
---|
.. | .. |
---|
1758 | 1761 | u64 lblock = (offset + (1 << bsize_shift) - 1) >> bsize_shift; |
---|
1759 | 1762 | __u16 start_list[GFS2_MAX_META_HEIGHT]; |
---|
1760 | 1763 | __u16 __end_list[GFS2_MAX_META_HEIGHT], *end_list = NULL; |
---|
1761 | | - unsigned int start_aligned, uninitialized_var(end_aligned); |
---|
| 1764 | + unsigned int start_aligned, end_aligned; |
---|
1762 | 1765 | unsigned int strip_h = ip->i_height - 1; |
---|
1763 | 1766 | u32 btotal = 0; |
---|
1764 | 1767 | int ret, state; |
---|
.. | .. |
---|
1863 | 1866 | gfs2_assert_withdraw(sdp, bh); |
---|
1864 | 1867 | if (gfs2_assert_withdraw(sdp, |
---|
1865 | 1868 | prev_bnr != bh->b_blocknr)) { |
---|
1866 | | - printk(KERN_EMERG "GFS2: fsid=%s:inode %llu, " |
---|
1867 | | - "block:%llu, i_h:%u, s_h:%u, mp_h:%u\n", |
---|
1868 | | - sdp->sd_fsname, |
---|
| 1869 | + fs_emerg(sdp, "inode %llu, block:%llu, i_h:%u," |
---|
| 1870 | + "s_h:%u, mp_h:%u\n", |
---|
1869 | 1871 | (unsigned long long)ip->i_no_addr, |
---|
1870 | 1872 | prev_bnr, ip->i_height, strip_h, mp_h); |
---|
1871 | 1873 | } |
---|
.. | .. |
---|
2141 | 2143 | if (error) |
---|
2142 | 2144 | goto do_end_trans; |
---|
2143 | 2145 | |
---|
2144 | | - i_size_write(inode, size); |
---|
| 2146 | + truncate_setsize(inode, size); |
---|
2145 | 2147 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode); |
---|
2146 | 2148 | gfs2_trans_add_meta(ip->i_gl, dibh); |
---|
2147 | 2149 | gfs2_dinode_out(ip, dibh->b_data); |
---|
.. | .. |
---|
2183 | 2185 | |
---|
2184 | 2186 | inode_dio_wait(inode); |
---|
2185 | 2187 | |
---|
2186 | | - ret = gfs2_rsqa_alloc(ip); |
---|
| 2188 | + ret = gfs2_qa_get(ip); |
---|
2187 | 2189 | if (ret) |
---|
2188 | 2190 | goto out; |
---|
2189 | 2191 | |
---|
.. | .. |
---|
2194 | 2196 | |
---|
2195 | 2197 | ret = do_shrink(inode, newsize); |
---|
2196 | 2198 | out: |
---|
2197 | | - gfs2_rsqa_delete(ip, NULL); |
---|
| 2199 | + gfs2_rs_delete(ip); |
---|
| 2200 | + gfs2_qa_put(ip); |
---|
2198 | 2201 | return ret; |
---|
2199 | 2202 | } |
---|
2200 | 2203 | |
---|
.. | .. |
---|
2223 | 2226 | struct gfs2_journal_extent *jext; |
---|
2224 | 2227 | |
---|
2225 | 2228 | while(!list_empty(&jd->extent_list)) { |
---|
2226 | | - jext = list_entry(jd->extent_list.next, struct gfs2_journal_extent, list); |
---|
| 2229 | + jext = list_first_entry(&jd->extent_list, struct gfs2_journal_extent, list); |
---|
2227 | 2230 | list_del(&jext->list); |
---|
2228 | 2231 | kfree(jext); |
---|
2229 | 2232 | } |
---|
.. | .. |
---|
2244 | 2247 | struct gfs2_journal_extent *jext; |
---|
2245 | 2248 | |
---|
2246 | 2249 | if (!list_empty(&jd->extent_list)) { |
---|
2247 | | - jext = list_entry(jd->extent_list.prev, struct gfs2_journal_extent, list); |
---|
| 2250 | + jext = list_last_entry(&jd->extent_list, struct gfs2_journal_extent, list); |
---|
2248 | 2251 | if ((jext->dblock + jext->blocks) == dblock) { |
---|
2249 | 2252 | jext->blocks += blocks; |
---|
2250 | 2253 | return 0; |
---|
.. | .. |
---|
2291 | 2294 | unsigned int shift = sdp->sd_sb.sb_bsize_shift; |
---|
2292 | 2295 | u64 size; |
---|
2293 | 2296 | int rc; |
---|
| 2297 | + ktime_t start, end; |
---|
2294 | 2298 | |
---|
| 2299 | + start = ktime_get(); |
---|
2295 | 2300 | lblock_stop = i_size_read(jd->jd_inode) >> shift; |
---|
2296 | 2301 | size = (lblock_stop - lblock) << shift; |
---|
2297 | 2302 | jd->nr_extents = 0; |
---|
.. | .. |
---|
2311 | 2316 | lblock += (bh.b_size >> ip->i_inode.i_blkbits); |
---|
2312 | 2317 | } while(size > 0); |
---|
2313 | 2318 | |
---|
2314 | | - fs_info(sdp, "journal %d mapped with %u extents\n", jd->jd_jid, |
---|
2315 | | - jd->nr_extents); |
---|
| 2319 | + end = ktime_get(); |
---|
| 2320 | + fs_info(sdp, "journal %d mapped with %u extents in %lldms\n", jd->jd_jid, |
---|
| 2321 | + jd->nr_extents, ktime_ms_delta(end, start)); |
---|
2316 | 2322 | return 0; |
---|
2317 | 2323 | |
---|
2318 | 2324 | fail: |
---|
.. | .. |
---|
2438 | 2444 | struct inode *inode = file_inode(file); |
---|
2439 | 2445 | struct gfs2_inode *ip = GFS2_I(inode); |
---|
2440 | 2446 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
---|
| 2447 | + unsigned int blocksize = i_blocksize(inode); |
---|
| 2448 | + loff_t start, end; |
---|
2441 | 2449 | int error; |
---|
2442 | 2450 | |
---|
2443 | | - if (gfs2_is_jdata(ip)) |
---|
2444 | | - error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA, |
---|
2445 | | - GFS2_JTRUNC_REVOKES); |
---|
2446 | | - else |
---|
2447 | | - error = gfs2_trans_begin(sdp, RES_DINODE, 0); |
---|
2448 | | - if (error) |
---|
2449 | | - return error; |
---|
| 2451 | + if (!gfs2_is_stuffed(ip)) { |
---|
| 2452 | + unsigned int start_off, end_len; |
---|
2450 | 2453 | |
---|
2451 | | - if (gfs2_is_stuffed(ip)) { |
---|
2452 | | - error = stuffed_zero_range(inode, offset, length); |
---|
2453 | | - if (error) |
---|
2454 | | - goto out; |
---|
2455 | | - } else { |
---|
2456 | | - unsigned int start_off, end_len, blocksize; |
---|
2457 | | - |
---|
2458 | | - blocksize = i_blocksize(inode); |
---|
2459 | 2454 | start_off = offset & (blocksize - 1); |
---|
2460 | 2455 | end_len = (offset + length) & (blocksize - 1); |
---|
2461 | 2456 | if (start_off) { |
---|
.. | .. |
---|
2474 | 2469 | if (error) |
---|
2475 | 2470 | goto out; |
---|
2476 | 2471 | } |
---|
| 2472 | + } |
---|
| 2473 | + |
---|
| 2474 | + start = round_down(offset, blocksize); |
---|
| 2475 | + end = round_up(offset + length, blocksize) - 1; |
---|
| 2476 | + error = filemap_write_and_wait_range(inode->i_mapping, start, end); |
---|
| 2477 | + if (error) |
---|
| 2478 | + return error; |
---|
| 2479 | + |
---|
| 2480 | + if (gfs2_is_jdata(ip)) |
---|
| 2481 | + error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA, |
---|
| 2482 | + GFS2_JTRUNC_REVOKES); |
---|
| 2483 | + else |
---|
| 2484 | + error = gfs2_trans_begin(sdp, RES_DINODE, 0); |
---|
| 2485 | + if (error) |
---|
| 2486 | + return error; |
---|
| 2487 | + |
---|
| 2488 | + if (gfs2_is_stuffed(ip)) { |
---|
| 2489 | + error = stuffed_zero_range(inode, offset, length); |
---|
| 2490 | + if (error) |
---|
| 2491 | + goto out; |
---|
2477 | 2492 | } |
---|
2478 | 2493 | |
---|
2479 | 2494 | if (gfs2_is_jdata(ip)) { |
---|
.. | .. |
---|
2496 | 2511 | gfs2_trans_end(sdp); |
---|
2497 | 2512 | return error; |
---|
2498 | 2513 | } |
---|
| 2514 | + |
---|
| 2515 | +static int gfs2_map_blocks(struct iomap_writepage_ctx *wpc, struct inode *inode, |
---|
| 2516 | + loff_t offset) |
---|
| 2517 | +{ |
---|
| 2518 | + struct metapath mp = { .mp_aheight = 1, }; |
---|
| 2519 | + int ret; |
---|
| 2520 | + |
---|
| 2521 | + if (WARN_ON_ONCE(gfs2_is_stuffed(GFS2_I(inode)))) |
---|
| 2522 | + return -EIO; |
---|
| 2523 | + |
---|
| 2524 | + if (offset >= wpc->iomap.offset && |
---|
| 2525 | + offset < wpc->iomap.offset + wpc->iomap.length) |
---|
| 2526 | + return 0; |
---|
| 2527 | + |
---|
| 2528 | + memset(&wpc->iomap, 0, sizeof(wpc->iomap)); |
---|
| 2529 | + ret = gfs2_iomap_get(inode, offset, INT_MAX, 0, &wpc->iomap, &mp); |
---|
| 2530 | + release_metapath(&mp); |
---|
| 2531 | + return ret; |
---|
| 2532 | +} |
---|
| 2533 | + |
---|
| 2534 | +const struct iomap_writeback_ops gfs2_writeback_ops = { |
---|
| 2535 | + .map_blocks = gfs2_map_blocks, |
---|
| 2536 | +}; |
---|