diff options
-rw-r--r-- | fs/ocfs2/slot_map.c | 128 |
1 files changed, 108 insertions, 20 deletions
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c index 762360d95e93..5bddee110091 100644 --- a/fs/ocfs2/slot_map.c +++ b/fs/ocfs2/slot_map.c | |||
@@ -44,7 +44,8 @@ | |||
44 | 44 | ||
45 | struct ocfs2_slot_info { | 45 | struct ocfs2_slot_info { |
46 | struct inode *si_inode; | 46 | struct inode *si_inode; |
47 | struct buffer_head *si_bh; | 47 | unsigned int si_blocks; |
48 | struct buffer_head **si_bh; | ||
48 | unsigned int si_num_slots; | 49 | unsigned int si_num_slots; |
49 | unsigned int si_size; | 50 | unsigned int si_size; |
50 | s16 si_global_node_nums[OCFS2_MAX_SLOTS]; | 51 | s16 si_global_node_nums[OCFS2_MAX_SLOTS]; |
@@ -68,7 +69,7 @@ static void ocfs2_update_slot_info(struct ocfs2_slot_info *si) | |||
68 | 69 | ||
69 | /* we don't read the slot block here as ocfs2_super_lock | 70 | /* we don't read the slot block here as ocfs2_super_lock |
70 | * should've made sure we have the most recent copy. */ | 71 | * should've made sure we have the most recent copy. */ |
71 | disk_info = (__le16 *) si->si_bh->b_data; | 72 | disk_info = (__le16 *) si->si_bh[0]->b_data; |
72 | 73 | ||
73 | for (i = 0; i < si->si_size; i++) | 74 | for (i = 0; i < si->si_size; i++) |
74 | si->si_global_node_nums[i] = le16_to_cpu(disk_info[i]); | 75 | si->si_global_node_nums[i] = le16_to_cpu(disk_info[i]); |
@@ -78,13 +79,23 @@ int ocfs2_refresh_slot_info(struct ocfs2_super *osb) | |||
78 | { | 79 | { |
79 | int ret; | 80 | int ret; |
80 | struct ocfs2_slot_info *si = osb->slot_info; | 81 | struct ocfs2_slot_info *si = osb->slot_info; |
81 | struct buffer_head *bh; | ||
82 | 82 | ||
83 | if (si == NULL) | 83 | if (si == NULL) |
84 | return 0; | 84 | return 0; |
85 | 85 | ||
86 | bh = si->si_bh; | 86 | BUG_ON(si->si_blocks == 0); |
87 | ret = ocfs2_read_block(osb, bh->b_blocknr, &bh, 0, si->si_inode); | 87 | BUG_ON(si->si_bh == NULL); |
88 | |||
89 | mlog(0, "Refreshing slot map, reading %u block(s)\n", | ||
90 | si->si_blocks); | ||
91 | |||
92 | /* | ||
93 | * We pass -1 as blocknr because we expect all of si->si_bh to | ||
94 | * be !NULL. Thus, ocfs2_read_blocks() will ignore blocknr. If | ||
95 | * this is not true, the read of -1 (UINT64_MAX) will fail. | ||
96 | */ | ||
97 | ret = ocfs2_read_blocks(osb, -1, si->si_blocks, si->si_bh, 0, | ||
98 | si->si_inode); | ||
88 | if (ret == 0) { | 99 | if (ret == 0) { |
89 | spin_lock(&osb->osb_lock); | 100 | spin_lock(&osb->osb_lock); |
90 | ocfs2_update_slot_info(si); | 101 | ocfs2_update_slot_info(si); |
@@ -100,20 +111,42 @@ static int ocfs2_update_disk_slots(struct ocfs2_super *osb, | |||
100 | struct ocfs2_slot_info *si) | 111 | struct ocfs2_slot_info *si) |
101 | { | 112 | { |
102 | int status, i; | 113 | int status, i; |
103 | __le16 *disk_info = (__le16 *) si->si_bh->b_data; | 114 | __le16 *disk_info = (__le16 *) si->si_bh[0]->b_data; |
104 | 115 | ||
105 | spin_lock(&osb->osb_lock); | 116 | spin_lock(&osb->osb_lock); |
106 | for (i = 0; i < si->si_size; i++) | 117 | for (i = 0; i < si->si_size; i++) |
107 | disk_info[i] = cpu_to_le16(si->si_global_node_nums[i]); | 118 | disk_info[i] = cpu_to_le16(si->si_global_node_nums[i]); |
108 | spin_unlock(&osb->osb_lock); | 119 | spin_unlock(&osb->osb_lock); |
109 | 120 | ||
110 | status = ocfs2_write_block(osb, si->si_bh, si->si_inode); | 121 | status = ocfs2_write_block(osb, si->si_bh[0], si->si_inode); |
111 | if (status < 0) | 122 | if (status < 0) |
112 | mlog_errno(status); | 123 | mlog_errno(status); |
113 | 124 | ||
114 | return status; | 125 | return status; |
115 | } | 126 | } |
116 | 127 | ||
128 | /* | ||
129 | * Calculate how many bytes are needed by the slot map. Returns | ||
130 | * an error if the slot map file is too small. | ||
131 | */ | ||
132 | static int ocfs2_slot_map_physical_size(struct ocfs2_super *osb, | ||
133 | struct inode *inode, | ||
134 | unsigned long long *bytes) | ||
135 | { | ||
136 | unsigned long long bytes_needed; | ||
137 | |||
138 | bytes_needed = osb->max_slots * sizeof(__le16); | ||
139 | if (bytes_needed > i_size_read(inode)) { | ||
140 | mlog(ML_ERROR, | ||
141 | "Slot map file is too small! (size %llu, needed %llu)\n", | ||
142 | i_size_read(inode), bytes_needed); | ||
143 | return -ENOSPC; | ||
144 | } | ||
145 | |||
146 | *bytes = bytes_needed; | ||
147 | return 0; | ||
148 | } | ||
149 | |||
117 | /* try to find global node in the slot info. Returns | 150 | /* try to find global node in the slot info. Returns |
118 | * OCFS2_INVALID_SLOT if nothing is found. */ | 151 | * OCFS2_INVALID_SLOT if nothing is found. */ |
119 | static s16 __ocfs2_node_num_to_slot(struct ocfs2_slot_info *si, | 152 | static s16 __ocfs2_node_num_to_slot(struct ocfs2_slot_info *si, |
@@ -188,13 +221,22 @@ int ocfs2_slot_to_node_num_locked(struct ocfs2_super *osb, int slot_num, | |||
188 | 221 | ||
189 | static void __ocfs2_free_slot_info(struct ocfs2_slot_info *si) | 222 | static void __ocfs2_free_slot_info(struct ocfs2_slot_info *si) |
190 | { | 223 | { |
224 | unsigned int i; | ||
225 | |||
191 | if (si == NULL) | 226 | if (si == NULL) |
192 | return; | 227 | return; |
193 | 228 | ||
194 | if (si->si_inode) | 229 | if (si->si_inode) |
195 | iput(si->si_inode); | 230 | iput(si->si_inode); |
196 | if (si->si_bh) | 231 | if (si->si_bh) { |
197 | brelse(si->si_bh); | 232 | for (i = 0; i < si->si_blocks; i++) { |
233 | if (si->si_bh[i]) { | ||
234 | brelse(si->si_bh[i]); | ||
235 | si->si_bh[i] = NULL; | ||
236 | } | ||
237 | } | ||
238 | kfree(si->si_bh); | ||
239 | } | ||
198 | 240 | ||
199 | kfree(si); | 241 | kfree(si); |
200 | } | 242 | } |
@@ -225,12 +267,65 @@ int ocfs2_clear_slot(struct ocfs2_super *osb, s16 slot_num) | |||
225 | return ocfs2_update_disk_slots(osb, osb->slot_info); | 267 | return ocfs2_update_disk_slots(osb, osb->slot_info); |
226 | } | 268 | } |
227 | 269 | ||
270 | static int ocfs2_map_slot_buffers(struct ocfs2_super *osb, | ||
271 | struct ocfs2_slot_info *si) | ||
272 | { | ||
273 | int status = 0; | ||
274 | u64 blkno; | ||
275 | unsigned long long blocks, bytes; | ||
276 | unsigned int i; | ||
277 | struct buffer_head *bh; | ||
278 | |||
279 | status = ocfs2_slot_map_physical_size(osb, si->si_inode, &bytes); | ||
280 | if (status) | ||
281 | goto bail; | ||
282 | |||
283 | blocks = ocfs2_blocks_for_bytes(si->si_inode->i_sb, bytes); | ||
284 | BUG_ON(blocks > UINT_MAX); | ||
285 | si->si_blocks = blocks; | ||
286 | if (!si->si_blocks) | ||
287 | goto bail; | ||
288 | |||
289 | mlog(0, "Slot map needs %u buffers for %llu bytes\n", | ||
290 | si->si_blocks, bytes); | ||
291 | |||
292 | si->si_bh = kzalloc(sizeof(struct buffer_head *) * si->si_blocks, | ||
293 | GFP_KERNEL); | ||
294 | if (!si->si_bh) { | ||
295 | status = -ENOMEM; | ||
296 | mlog_errno(status); | ||
297 | goto bail; | ||
298 | } | ||
299 | |||
300 | for (i = 0; i < si->si_blocks; i++) { | ||
301 | status = ocfs2_extent_map_get_blocks(si->si_inode, i, | ||
302 | &blkno, NULL, NULL); | ||
303 | if (status < 0) { | ||
304 | mlog_errno(status); | ||
305 | goto bail; | ||
306 | } | ||
307 | |||
308 | mlog(0, "Reading slot map block %u at %llu\n", i, | ||
309 | (unsigned long long)blkno); | ||
310 | |||
311 | bh = NULL; /* Acquire a fresh bh */ | ||
312 | status = ocfs2_read_block(osb, blkno, &bh, 0, si->si_inode); | ||
313 | if (status < 0) { | ||
314 | mlog_errno(status); | ||
315 | goto bail; | ||
316 | } | ||
317 | |||
318 | si->si_bh[i] = bh; | ||
319 | } | ||
320 | |||
321 | bail: | ||
322 | return status; | ||
323 | } | ||
324 | |||
228 | int ocfs2_init_slot_info(struct ocfs2_super *osb) | 325 | int ocfs2_init_slot_info(struct ocfs2_super *osb) |
229 | { | 326 | { |
230 | int status, i; | 327 | int status, i; |
231 | u64 blkno; | ||
232 | struct inode *inode = NULL; | 328 | struct inode *inode = NULL; |
233 | struct buffer_head *bh = NULL; | ||
234 | struct ocfs2_slot_info *si; | 329 | struct ocfs2_slot_info *si; |
235 | 330 | ||
236 | si = kzalloc(sizeof(struct ocfs2_slot_info), GFP_KERNEL); | 331 | si = kzalloc(sizeof(struct ocfs2_slot_info), GFP_KERNEL); |
@@ -254,20 +349,13 @@ int ocfs2_init_slot_info(struct ocfs2_super *osb) | |||
254 | goto bail; | 349 | goto bail; |
255 | } | 350 | } |
256 | 351 | ||
257 | status = ocfs2_extent_map_get_blocks(inode, 0ULL, &blkno, NULL, NULL); | 352 | si->si_inode = inode; |
258 | if (status < 0) { | 353 | status = ocfs2_map_slot_buffers(osb, si); |
259 | mlog_errno(status); | ||
260 | goto bail; | ||
261 | } | ||
262 | |||
263 | status = ocfs2_read_block(osb, blkno, &bh, 0, inode); | ||
264 | if (status < 0) { | 354 | if (status < 0) { |
265 | mlog_errno(status); | 355 | mlog_errno(status); |
266 | goto bail; | 356 | goto bail; |
267 | } | 357 | } |
268 | 358 | ||
269 | si->si_inode = inode; | ||
270 | si->si_bh = bh; | ||
271 | osb->slot_info = (struct ocfs2_slot_info *)si; | 359 | osb->slot_info = (struct ocfs2_slot_info *)si; |
272 | bail: | 360 | bail: |
273 | if (status < 0 && si) | 361 | if (status < 0 && si) |