Commit | Line | Data |
---|---|---|
b3b94faa DT |
1 | /* |
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
3 | * Copyright (C) 2004-2005 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 v.2. | |
8 | */ | |
9 | ||
10 | #include <linux/sched.h> | |
11 | #include <linux/slab.h> | |
12 | #include <linux/spinlock.h> | |
13 | #include <linux/completion.h> | |
14 | #include <linux/buffer_head.h> | |
15 | #include <linux/mm.h> | |
16 | #include <linux/pagemap.h> | |
17 | #include <linux/writeback.h> | |
18 | #include <linux/swap.h> | |
19 | #include <linux/delay.h> | |
20 | #include <asm/semaphore.h> | |
21 | ||
22 | #include "gfs2.h" | |
23 | #include "glock.h" | |
24 | #include "glops.h" | |
25 | #include "inode.h" | |
26 | #include "log.h" | |
27 | #include "lops.h" | |
28 | #include "meta_io.h" | |
29 | #include "rgrp.h" | |
30 | #include "trans.h" | |
31 | ||
32 | #define buffer_busy(bh) \ | |
33 | ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) | |
34 | #define buffer_in_io(bh) \ | |
35 | ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock))) | |
36 | ||
37 | static int aspace_get_block(struct inode *inode, sector_t lblock, | |
38 | struct buffer_head *bh_result, int create) | |
39 | { | |
40 | gfs2_assert_warn(get_v2sdp(inode->i_sb), 0); | |
41 | return -EOPNOTSUPP; | |
42 | } | |
43 | ||
44 | static int gfs2_aspace_writepage(struct page *page, | |
45 | struct writeback_control *wbc) | |
46 | { | |
47 | return block_write_full_page(page, aspace_get_block, wbc); | |
48 | } | |
49 | ||
50 | /** | |
51 | * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. | |
52 | * @bh: the buffer we're stuck on | |
53 | * | |
54 | */ | |
55 | ||
56 | static void stuck_releasepage(struct buffer_head *bh) | |
57 | { | |
58 | struct gfs2_sbd *sdp = get_v2sdp(bh->b_page->mapping->host->i_sb); | |
59 | struct gfs2_bufdata *bd = get_v2bd(bh); | |
60 | struct gfs2_glock *gl; | |
61 | ||
62 | fs_warn(sdp, "stuck in gfs2_releasepage()\n"); | |
63 | fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n", | |
64 | (uint64_t)bh->b_blocknr, atomic_read(&bh->b_count)); | |
65 | fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh)); | |
66 | fs_warn(sdp, "get_v2bd(bh) = %s\n", (bd) ? "!NULL" : "NULL"); | |
67 | ||
68 | if (!bd) | |
69 | return; | |
70 | ||
71 | gl = bd->bd_gl; | |
72 | ||
73 | fs_warn(sdp, "gl = (%u, %llu)\n", | |
74 | gl->gl_name.ln_type, gl->gl_name.ln_number); | |
75 | ||
76 | fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n", | |
77 | (list_empty(&bd->bd_list_tr)) ? "no" : "yes", | |
78 | (list_empty(&bd->bd_le.le_list)) ? "no" : "yes"); | |
79 | ||
80 | if (gl->gl_ops == &gfs2_inode_glops) { | |
81 | struct gfs2_inode *ip = get_gl2ip(gl); | |
82 | unsigned int x; | |
83 | ||
84 | if (!ip) | |
85 | return; | |
86 | ||
87 | fs_warn(sdp, "ip = %llu %llu\n", | |
88 | ip->i_num.no_formal_ino, ip->i_num.no_addr); | |
89 | fs_warn(sdp, "ip->i_count = %d, ip->i_vnode = %s\n", | |
90 | atomic_read(&ip->i_count), | |
91 | (ip->i_vnode) ? "!NULL" : "NULL"); | |
92 | ||
93 | for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) | |
94 | fs_warn(sdp, "ip->i_cache[%u] = %s\n", | |
95 | x, (ip->i_cache[x]) ? "!NULL" : "NULL"); | |
96 | } | |
97 | } | |
98 | ||
99 | /** | |
100 | * gfs2_aspace_releasepage - free the metadata associated with a page | |
101 | * @page: the page that's being released | |
102 | * @gfp_mask: passed from Linux VFS, ignored by us | |
103 | * | |
104 | * Call try_to_free_buffers() if the buffers in this page can be | |
105 | * released. | |
106 | * | |
107 | * Returns: 0 | |
108 | */ | |
109 | ||
110 | static int gfs2_aspace_releasepage(struct page *page, gfp_t gfp_mask) | |
111 | { | |
112 | struct inode *aspace = page->mapping->host; | |
113 | struct gfs2_sbd *sdp = get_v2sdp(aspace->i_sb); | |
114 | struct buffer_head *bh, *head; | |
115 | struct gfs2_bufdata *bd; | |
116 | unsigned long t; | |
117 | ||
118 | if (!page_has_buffers(page)) | |
119 | goto out; | |
120 | ||
121 | head = bh = page_buffers(page); | |
122 | do { | |
123 | t = jiffies; | |
124 | ||
125 | while (atomic_read(&bh->b_count)) { | |
126 | if (atomic_read(&aspace->i_writecount)) { | |
127 | if (time_after_eq(jiffies, t + | |
128 | gfs2_tune_get(sdp, gt_stall_secs) * HZ)) { | |
129 | stuck_releasepage(bh); | |
130 | t = jiffies; | |
131 | } | |
132 | ||
133 | yield(); | |
134 | continue; | |
135 | } | |
136 | ||
137 | return 0; | |
138 | } | |
139 | ||
140 | gfs2_assert_warn(sdp, !buffer_pinned(bh)); | |
141 | ||
142 | bd = get_v2bd(bh); | |
143 | if (bd) { | |
144 | gfs2_assert_warn(sdp, bd->bd_bh == bh); | |
145 | gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr)); | |
146 | gfs2_assert_warn(sdp, list_empty(&bd->bd_le.le_list)); | |
147 | gfs2_assert_warn(sdp, !bd->bd_ail); | |
148 | kmem_cache_free(gfs2_bufdata_cachep, bd); | |
b3b94faa DT |
149 | set_v2bd(bh, NULL); |
150 | } | |
151 | ||
152 | bh = bh->b_this_page; | |
153 | } | |
154 | while (bh != head); | |
155 | ||
156 | out: | |
157 | return try_to_free_buffers(page); | |
158 | } | |
159 | ||
160 | static struct address_space_operations aspace_aops = { | |
161 | .writepage = gfs2_aspace_writepage, | |
162 | .releasepage = gfs2_aspace_releasepage, | |
163 | }; | |
164 | ||
165 | /** | |
166 | * gfs2_aspace_get - Create and initialize a struct inode structure | |
167 | * @sdp: the filesystem the aspace is in | |
168 | * | |
169 | * Right now a struct inode is just a struct inode. Maybe Linux | |
170 | * will supply a more lightweight address space construct (that works) | |
171 | * in the future. | |
172 | * | |
173 | * Make sure pages/buffers in this aspace aren't in high memory. | |
174 | * | |
175 | * Returns: the aspace | |
176 | */ | |
177 | ||
178 | struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) | |
179 | { | |
180 | struct inode *aspace; | |
181 | ||
182 | aspace = new_inode(sdp->sd_vfs); | |
183 | if (aspace) { | |
184 | mapping_set_gfp_mask(aspace->i_mapping, GFP_KERNEL); | |
185 | aspace->i_mapping->a_ops = &aspace_aops; | |
186 | aspace->i_size = ~0ULL; | |
187 | set_v2ip(aspace, NULL); | |
188 | insert_inode_hash(aspace); | |
189 | } | |
190 | ||
191 | return aspace; | |
192 | } | |
193 | ||
194 | void gfs2_aspace_put(struct inode *aspace) | |
195 | { | |
196 | remove_inode_hash(aspace); | |
197 | iput(aspace); | |
198 | } | |
199 | ||
200 | /** | |
201 | * gfs2_ail1_start_one - Start I/O on a part of the AIL | |
202 | * @sdp: the filesystem | |
203 | * @tr: the part of the AIL | |
204 | * | |
205 | */ | |
206 | ||
207 | void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |
208 | { | |
209 | struct gfs2_bufdata *bd, *s; | |
210 | struct buffer_head *bh; | |
211 | int retry; | |
212 | ||
213 | do { | |
214 | retry = 0; | |
215 | ||
216 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, | |
217 | bd_ail_st_list) { | |
218 | bh = bd->bd_bh; | |
219 | ||
220 | gfs2_assert(sdp, bd->bd_ail == ai); | |
221 | ||
222 | if (!buffer_busy(bh)) { | |
223 | if (!buffer_uptodate(bh)) | |
224 | gfs2_io_error_bh(sdp, bh); | |
225 | list_move(&bd->bd_ail_st_list, | |
226 | &ai->ai_ail2_list); | |
227 | continue; | |
228 | } | |
229 | ||
230 | if (!buffer_dirty(bh)) | |
231 | continue; | |
232 | ||
233 | list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); | |
234 | ||
235 | gfs2_log_unlock(sdp); | |
236 | wait_on_buffer(bh); | |
237 | ll_rw_block(WRITE, 1, &bh); | |
238 | gfs2_log_lock(sdp); | |
239 | ||
240 | retry = 1; | |
241 | break; | |
242 | } | |
243 | } while (retry); | |
244 | } | |
245 | ||
246 | /** | |
247 | * gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced | |
248 | * @sdp: the filesystem | |
249 | * @ai: the AIL entry | |
250 | * | |
251 | */ | |
252 | ||
253 | int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags) | |
254 | { | |
255 | struct gfs2_bufdata *bd, *s; | |
256 | struct buffer_head *bh; | |
257 | ||
258 | list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, | |
259 | bd_ail_st_list) { | |
260 | bh = bd->bd_bh; | |
261 | ||
262 | gfs2_assert(sdp, bd->bd_ail == ai); | |
263 | ||
264 | if (buffer_busy(bh)) { | |
265 | if (flags & DIO_ALL) | |
266 | continue; | |
267 | else | |
268 | break; | |
269 | } | |
270 | ||
271 | if (!buffer_uptodate(bh)) | |
272 | gfs2_io_error_bh(sdp, bh); | |
273 | ||
274 | list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); | |
275 | } | |
276 | ||
277 | return list_empty(&ai->ai_ail1_list); | |
278 | } | |
279 | ||
280 | /** | |
281 | * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced | |
282 | * @sdp: the filesystem | |
283 | * @ai: the AIL entry | |
284 | * | |
285 | */ | |
286 | ||
287 | void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |
288 | { | |
289 | struct list_head *head = &ai->ai_ail2_list; | |
290 | struct gfs2_bufdata *bd; | |
291 | ||
292 | while (!list_empty(head)) { | |
293 | bd = list_entry(head->prev, struct gfs2_bufdata, | |
294 | bd_ail_st_list); | |
295 | gfs2_assert(sdp, bd->bd_ail == ai); | |
296 | bd->bd_ail = NULL; | |
297 | list_del(&bd->bd_ail_st_list); | |
298 | list_del(&bd->bd_ail_gl_list); | |
299 | atomic_dec(&bd->bd_gl->gl_ail_count); | |
300 | brelse(bd->bd_bh); | |
301 | } | |
302 | } | |
303 | ||
304 | /** | |
305 | * ail_empty_gl - remove all buffers for a given lock from the AIL | |
306 | * @gl: the glock | |
307 | * | |
308 | * None of the buffers should be dirty, locked, or pinned. | |
309 | */ | |
310 | ||
311 | void gfs2_ail_empty_gl(struct gfs2_glock *gl) | |
312 | { | |
313 | struct gfs2_sbd *sdp = gl->gl_sbd; | |
314 | unsigned int blocks; | |
315 | struct list_head *head = &gl->gl_ail_list; | |
316 | struct gfs2_bufdata *bd; | |
317 | struct buffer_head *bh; | |
318 | uint64_t blkno; | |
319 | int error; | |
320 | ||
321 | blocks = atomic_read(&gl->gl_ail_count); | |
322 | if (!blocks) | |
323 | return; | |
324 | ||
325 | error = gfs2_trans_begin(sdp, 0, blocks); | |
326 | if (gfs2_assert_withdraw(sdp, !error)) | |
327 | return; | |
328 | ||
329 | gfs2_log_lock(sdp); | |
330 | while (!list_empty(head)) { | |
331 | bd = list_entry(head->next, struct gfs2_bufdata, | |
332 | bd_ail_gl_list); | |
333 | bh = bd->bd_bh; | |
334 | blkno = bh->b_blocknr; | |
335 | gfs2_assert_withdraw(sdp, !buffer_busy(bh)); | |
336 | ||
337 | bd->bd_ail = NULL; | |
338 | list_del(&bd->bd_ail_st_list); | |
339 | list_del(&bd->bd_ail_gl_list); | |
340 | atomic_dec(&gl->gl_ail_count); | |
341 | brelse(bh); | |
342 | gfs2_log_unlock(sdp); | |
343 | ||
344 | gfs2_trans_add_revoke(sdp, blkno); | |
345 | ||
346 | gfs2_log_lock(sdp); | |
347 | } | |
348 | gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); | |
349 | gfs2_log_unlock(sdp); | |
350 | ||
351 | gfs2_trans_end(sdp); | |
352 | gfs2_log_flush(sdp); | |
353 | } | |
354 | ||
355 | /** | |
356 | * gfs2_meta_inval - Invalidate all buffers associated with a glock | |
357 | * @gl: the glock | |
358 | * | |
359 | */ | |
360 | ||
361 | void gfs2_meta_inval(struct gfs2_glock *gl) | |
362 | { | |
363 | struct gfs2_sbd *sdp = gl->gl_sbd; | |
364 | struct inode *aspace = gl->gl_aspace; | |
365 | struct address_space *mapping = gl->gl_aspace->i_mapping; | |
366 | ||
367 | gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); | |
368 | ||
369 | atomic_inc(&aspace->i_writecount); | |
370 | truncate_inode_pages(mapping, 0); | |
371 | atomic_dec(&aspace->i_writecount); | |
372 | ||
373 | gfs2_assert_withdraw(sdp, !mapping->nrpages); | |
374 | } | |
375 | ||
376 | /** | |
377 | * gfs2_meta_sync - Sync all buffers associated with a glock | |
378 | * @gl: The glock | |
379 | * @flags: DIO_START | DIO_WAIT | |
380 | * | |
381 | */ | |
382 | ||
383 | void gfs2_meta_sync(struct gfs2_glock *gl, int flags) | |
384 | { | |
385 | struct address_space *mapping = gl->gl_aspace->i_mapping; | |
386 | int error = 0; | |
387 | ||
388 | if (flags & DIO_START) | |
389 | filemap_fdatawrite(mapping); | |
390 | if (!error && (flags & DIO_WAIT)) | |
391 | error = filemap_fdatawait(mapping); | |
392 | ||
393 | if (error) | |
394 | gfs2_io_error(gl->gl_sbd); | |
395 | } | |
396 | ||
397 | /** | |
398 | * getbuf - Get a buffer with a given address space | |
399 | * @sdp: the filesystem | |
400 | * @aspace: the address space | |
401 | * @blkno: the block number (filesystem scope) | |
402 | * @create: 1 if the buffer should be created | |
403 | * | |
404 | * Returns: the buffer | |
405 | */ | |
406 | ||
407 | static struct buffer_head *getbuf(struct gfs2_sbd *sdp, struct inode *aspace, | |
408 | uint64_t blkno, int create) | |
409 | { | |
410 | struct page *page; | |
411 | struct buffer_head *bh; | |
412 | unsigned int shift; | |
413 | unsigned long index; | |
414 | unsigned int bufnum; | |
415 | ||
416 | shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift; | |
417 | index = blkno >> shift; /* convert block to page */ | |
418 | bufnum = blkno - (index << shift); /* block buf index within page */ | |
419 | ||
420 | if (create) { | |
421 | for (;;) { | |
422 | page = grab_cache_page(aspace->i_mapping, index); | |
423 | if (page) | |
424 | break; | |
425 | yield(); | |
426 | } | |
427 | } else { | |
428 | page = find_lock_page(aspace->i_mapping, index); | |
429 | if (!page) | |
430 | return NULL; | |
431 | } | |
432 | ||
433 | if (!page_has_buffers(page)) | |
434 | create_empty_buffers(page, sdp->sd_sb.sb_bsize, 0); | |
435 | ||
436 | /* Locate header for our buffer within our page */ | |
437 | for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page) | |
438 | /* Do nothing */; | |
439 | get_bh(bh); | |
440 | ||
441 | if (!buffer_mapped(bh)) | |
442 | map_bh(bh, sdp->sd_vfs, blkno); | |
443 | ||
444 | unlock_page(page); | |
445 | mark_page_accessed(page); | |
446 | page_cache_release(page); | |
447 | ||
448 | return bh; | |
449 | } | |
450 | ||
451 | static void meta_prep_new(struct buffer_head *bh) | |
452 | { | |
453 | struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; | |
454 | ||
455 | lock_buffer(bh); | |
456 | clear_buffer_dirty(bh); | |
457 | set_buffer_uptodate(bh); | |
458 | unlock_buffer(bh); | |
459 | ||
460 | mh->mh_magic = cpu_to_be32(GFS2_MAGIC); | |
461 | } | |
462 | ||
463 | /** | |
464 | * gfs2_meta_new - Get a block | |
465 | * @gl: The glock associated with this block | |
466 | * @blkno: The block number | |
467 | * | |
468 | * Returns: The buffer | |
469 | */ | |
470 | ||
471 | struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, uint64_t blkno) | |
472 | { | |
473 | struct buffer_head *bh; | |
474 | bh = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); | |
475 | meta_prep_new(bh); | |
476 | return bh; | |
477 | } | |
478 | ||
479 | /** | |
480 | * gfs2_meta_read - Read a block from disk | |
481 | * @gl: The glock covering the block | |
482 | * @blkno: The block number | |
483 | * @flags: flags to gfs2_dreread() | |
484 | * @bhp: the place where the buffer is returned (NULL on failure) | |
485 | * | |
486 | * Returns: errno | |
487 | */ | |
488 | ||
489 | int gfs2_meta_read(struct gfs2_glock *gl, uint64_t blkno, int flags, | |
490 | struct buffer_head **bhp) | |
491 | { | |
492 | int error; | |
493 | ||
494 | *bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); | |
495 | error = gfs2_meta_reread(gl->gl_sbd, *bhp, flags); | |
496 | if (error) | |
497 | brelse(*bhp); | |
498 | ||
499 | return error; | |
500 | } | |
501 | ||
502 | /** | |
503 | * gfs2_meta_reread - Reread a block from disk | |
504 | * @sdp: the filesystem | |
505 | * @bh: The block to read | |
506 | * @flags: Flags that control the read | |
507 | * | |
508 | * Returns: errno | |
509 | */ | |
510 | ||
511 | int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags) | |
512 | { | |
513 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | |
514 | return -EIO; | |
515 | ||
516 | if (flags & DIO_FORCE) | |
517 | clear_buffer_uptodate(bh); | |
518 | ||
519 | if ((flags & DIO_START) && !buffer_uptodate(bh)) | |
520 | ll_rw_block(READ, 1, &bh); | |
521 | ||
522 | if (flags & DIO_WAIT) { | |
523 | wait_on_buffer(bh); | |
524 | ||
525 | if (!buffer_uptodate(bh)) { | |
526 | struct gfs2_trans *tr = get_transaction; | |
527 | if (tr && tr->tr_touched) | |
528 | gfs2_io_error_bh(sdp, bh); | |
529 | return -EIO; | |
530 | } | |
531 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | |
532 | return -EIO; | |
533 | } | |
534 | ||
535 | return 0; | |
536 | } | |
537 | ||
538 | /** | |
586dfdaa | 539 | * gfs2_attach_bufdata - attach a struct gfs2_bufdata structure to a buffer |
b3b94faa DT |
540 | * @gl: the glock the buffer belongs to |
541 | * @bh: The buffer to be attached to | |
586dfdaa | 542 | * @meta: Flag to indicate whether its metadata or not |
b3b94faa DT |
543 | */ |
544 | ||
568f4c96 SW |
545 | void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, |
546 | int meta) | |
b3b94faa DT |
547 | { |
548 | struct gfs2_bufdata *bd; | |
549 | ||
18ec7d5c SW |
550 | if (meta) |
551 | lock_page(bh->b_page); | |
b3b94faa DT |
552 | |
553 | if (get_v2bd(bh)) { | |
18ec7d5c SW |
554 | if (meta) |
555 | unlock_page(bh->b_page); | |
b3b94faa DT |
556 | return; |
557 | } | |
558 | ||
f55ab26a | 559 | bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL), |
b3b94faa DT |
560 | memset(bd, 0, sizeof(struct gfs2_bufdata)); |
561 | ||
562 | bd->bd_bh = bh; | |
563 | bd->bd_gl = gl; | |
564 | ||
565 | INIT_LIST_HEAD(&bd->bd_list_tr); | |
18ec7d5c | 566 | if (meta) { |
586dfdaa | 567 | lops_init_le(&bd->bd_le, &gfs2_buf_lops); |
18ec7d5c | 568 | } else { |
586dfdaa | 569 | lops_init_le(&bd->bd_le, &gfs2_databuf_lops); |
18ec7d5c SW |
570 | get_bh(bh); |
571 | } | |
b3b94faa DT |
572 | set_v2bd(bh, bd); |
573 | ||
18ec7d5c SW |
574 | if (meta) |
575 | unlock_page(bh->b_page); | |
b3b94faa DT |
576 | } |
577 | ||
578 | /** | |
a98ab220 | 579 | * gfs2_pin - Pin a buffer in memory |
b3b94faa DT |
580 | * @sdp: the filesystem the buffer belongs to |
581 | * @bh: The buffer to be pinned | |
582 | * | |
583 | */ | |
584 | ||
a98ab220 | 585 | void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) |
b3b94faa DT |
586 | { |
587 | struct gfs2_bufdata *bd = get_v2bd(bh); | |
588 | ||
589 | gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); | |
590 | ||
591 | if (test_set_buffer_pinned(bh)) | |
592 | gfs2_assert_withdraw(sdp, 0); | |
593 | ||
594 | wait_on_buffer(bh); | |
595 | ||
596 | /* If this buffer is in the AIL and it has already been written | |
597 | to in-place disk block, remove it from the AIL. */ | |
598 | ||
599 | gfs2_log_lock(sdp); | |
600 | if (bd->bd_ail && !buffer_in_io(bh)) | |
601 | list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); | |
602 | gfs2_log_unlock(sdp); | |
603 | ||
604 | clear_buffer_dirty(bh); | |
605 | wait_on_buffer(bh); | |
606 | ||
607 | if (!buffer_uptodate(bh)) | |
608 | gfs2_io_error_bh(sdp, bh); | |
609 | ||
610 | get_bh(bh); | |
611 | } | |
612 | ||
613 | /** | |
a98ab220 | 614 | * gfs2_unpin - Unpin a buffer |
b3b94faa DT |
615 | * @sdp: the filesystem the buffer belongs to |
616 | * @bh: The buffer to unpin | |
617 | * @ai: | |
618 | * | |
619 | */ | |
620 | ||
a98ab220 SW |
621 | void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, |
622 | struct gfs2_ail *ai) | |
b3b94faa DT |
623 | { |
624 | struct gfs2_bufdata *bd = get_v2bd(bh); | |
625 | ||
626 | gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); | |
627 | ||
628 | if (!buffer_pinned(bh)) | |
629 | gfs2_assert_withdraw(sdp, 0); | |
630 | ||
631 | mark_buffer_dirty(bh); | |
632 | clear_buffer_pinned(bh); | |
633 | ||
634 | gfs2_log_lock(sdp); | |
635 | if (bd->bd_ail) { | |
636 | list_del(&bd->bd_ail_st_list); | |
637 | brelse(bh); | |
638 | } else { | |
639 | struct gfs2_glock *gl = bd->bd_gl; | |
640 | list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); | |
641 | atomic_inc(&gl->gl_ail_count); | |
642 | } | |
643 | bd->bd_ail = ai; | |
644 | list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); | |
645 | gfs2_log_unlock(sdp); | |
646 | } | |
647 | ||
648 | /** | |
649 | * gfs2_meta_wipe - make inode's buffers so they aren't dirty/pinned anymore | |
650 | * @ip: the inode who owns the buffers | |
651 | * @bstart: the first buffer in the run | |
652 | * @blen: the number of buffers in the run | |
653 | * | |
654 | */ | |
655 | ||
656 | void gfs2_meta_wipe(struct gfs2_inode *ip, uint64_t bstart, uint32_t blen) | |
657 | { | |
658 | struct gfs2_sbd *sdp = ip->i_sbd; | |
659 | struct inode *aspace = ip->i_gl->gl_aspace; | |
660 | struct buffer_head *bh; | |
661 | ||
662 | while (blen) { | |
663 | bh = getbuf(sdp, aspace, bstart, NO_CREATE); | |
664 | if (bh) { | |
665 | struct gfs2_bufdata *bd = get_v2bd(bh); | |
666 | ||
667 | if (test_clear_buffer_pinned(bh)) { | |
668 | gfs2_log_lock(sdp); | |
669 | list_del_init(&bd->bd_le.le_list); | |
670 | gfs2_assert_warn(sdp, sdp->sd_log_num_buf); | |
671 | sdp->sd_log_num_buf--; | |
672 | gfs2_log_unlock(sdp); | |
673 | get_transaction->tr_num_buf_rm++; | |
674 | brelse(bh); | |
675 | } | |
676 | if (bd) { | |
677 | gfs2_log_lock(sdp); | |
678 | if (bd->bd_ail) { | |
679 | uint64_t blkno = bh->b_blocknr; | |
680 | bd->bd_ail = NULL; | |
681 | list_del(&bd->bd_ail_st_list); | |
682 | list_del(&bd->bd_ail_gl_list); | |
683 | atomic_dec(&bd->bd_gl->gl_ail_count); | |
684 | brelse(bh); | |
685 | gfs2_log_unlock(sdp); | |
686 | gfs2_trans_add_revoke(sdp, blkno); | |
687 | } else | |
688 | gfs2_log_unlock(sdp); | |
689 | } | |
690 | ||
691 | lock_buffer(bh); | |
692 | clear_buffer_dirty(bh); | |
693 | clear_buffer_uptodate(bh); | |
694 | unlock_buffer(bh); | |
695 | ||
696 | brelse(bh); | |
697 | } | |
698 | ||
699 | bstart++; | |
700 | blen--; | |
701 | } | |
702 | } | |
703 | ||
704 | /** | |
705 | * gfs2_meta_cache_flush - get rid of any references on buffers for this inode | |
706 | * @ip: The GFS2 inode | |
707 | * | |
708 | * This releases buffers that are in the most-recently-used array of | |
709 | * blocks used for indirect block addressing for this inode. | |
710 | */ | |
711 | ||
712 | void gfs2_meta_cache_flush(struct gfs2_inode *ip) | |
713 | { | |
714 | struct buffer_head **bh_slot; | |
715 | unsigned int x; | |
716 | ||
717 | spin_lock(&ip->i_spin); | |
718 | ||
719 | for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) { | |
720 | bh_slot = &ip->i_cache[x]; | |
721 | if (!*bh_slot) | |
722 | break; | |
723 | brelse(*bh_slot); | |
724 | *bh_slot = NULL; | |
725 | } | |
726 | ||
727 | spin_unlock(&ip->i_spin); | |
728 | } | |
729 | ||
730 | /** | |
731 | * gfs2_meta_indirect_buffer - Get a metadata buffer | |
732 | * @ip: The GFS2 inode | |
733 | * @height: The level of this buf in the metadata (indir addr) tree (if any) | |
734 | * @num: The block number (device relative) of the buffer | |
735 | * @new: Non-zero if we may create a new buffer | |
736 | * @bhp: the buffer is returned here | |
737 | * | |
738 | * Try to use the gfs2_inode's MRU metadata tree cache. | |
739 | * | |
740 | * Returns: errno | |
741 | */ | |
742 | ||
743 | int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, uint64_t num, | |
744 | int new, struct buffer_head **bhp) | |
745 | { | |
746 | struct buffer_head *bh, **bh_slot = ip->i_cache + height; | |
747 | int error; | |
748 | ||
749 | spin_lock(&ip->i_spin); | |
750 | bh = *bh_slot; | |
751 | if (bh) { | |
752 | if (bh->b_blocknr == num) | |
753 | get_bh(bh); | |
754 | else | |
755 | bh = NULL; | |
756 | } | |
757 | spin_unlock(&ip->i_spin); | |
758 | ||
759 | if (bh) { | |
760 | if (new) | |
761 | meta_prep_new(bh); | |
762 | else { | |
763 | error = gfs2_meta_reread(ip->i_sbd, bh, | |
764 | DIO_START | DIO_WAIT); | |
765 | if (error) { | |
766 | brelse(bh); | |
767 | return error; | |
768 | } | |
769 | } | |
770 | } else { | |
771 | if (new) | |
772 | bh = gfs2_meta_new(ip->i_gl, num); | |
773 | else { | |
774 | error = gfs2_meta_read(ip->i_gl, num, | |
775 | DIO_START | DIO_WAIT, &bh); | |
776 | if (error) | |
777 | return error; | |
778 | } | |
779 | ||
780 | spin_lock(&ip->i_spin); | |
781 | if (*bh_slot != bh) { | |
782 | brelse(*bh_slot); | |
783 | *bh_slot = bh; | |
784 | get_bh(bh); | |
785 | } | |
786 | spin_unlock(&ip->i_spin); | |
787 | } | |
788 | ||
789 | if (new) { | |
790 | if (gfs2_assert_warn(ip->i_sbd, height)) { | |
791 | brelse(bh); | |
792 | return -EIO; | |
793 | } | |
d4e9c4c3 | 794 | gfs2_trans_add_bh(ip->i_gl, bh, 1); |
b3b94faa DT |
795 | gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); |
796 | gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); | |
797 | ||
798 | } else if (gfs2_metatype_check(ip->i_sbd, bh, | |
799 | (height) ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)) { | |
800 | brelse(bh); | |
801 | return -EIO; | |
802 | } | |
803 | ||
804 | *bhp = bh; | |
805 | ||
806 | return 0; | |
807 | } | |
808 | ||
809 | /** | |
810 | * gfs2_meta_ra - start readahead on an extent of a file | |
811 | * @gl: the glock the blocks belong to | |
812 | * @dblock: the starting disk block | |
813 | * @extlen: the number of blocks in the extent | |
814 | * | |
815 | */ | |
816 | ||
817 | void gfs2_meta_ra(struct gfs2_glock *gl, uint64_t dblock, uint32_t extlen) | |
818 | { | |
819 | struct gfs2_sbd *sdp = gl->gl_sbd; | |
820 | struct inode *aspace = gl->gl_aspace; | |
821 | struct buffer_head *first_bh, *bh; | |
568f4c96 SW |
822 | uint32_t max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> |
823 | sdp->sd_sb.sb_bsize_shift; | |
b3b94faa DT |
824 | int error; |
825 | ||
826 | if (!extlen || !max_ra) | |
827 | return; | |
828 | if (extlen > max_ra) | |
829 | extlen = max_ra; | |
830 | ||
831 | first_bh = getbuf(sdp, aspace, dblock, CREATE); | |
832 | ||
833 | if (buffer_uptodate(first_bh)) | |
834 | goto out; | |
835 | if (!buffer_locked(first_bh)) { | |
836 | error = gfs2_meta_reread(sdp, first_bh, DIO_START); | |
837 | if (error) | |
838 | goto out; | |
839 | } | |
840 | ||
841 | dblock++; | |
842 | extlen--; | |
843 | ||
844 | while (extlen) { | |
845 | bh = getbuf(sdp, aspace, dblock, CREATE); | |
846 | ||
847 | if (!buffer_uptodate(bh) && !buffer_locked(bh)) { | |
848 | error = gfs2_meta_reread(sdp, bh, DIO_START); | |
849 | brelse(bh); | |
850 | if (error) | |
851 | goto out; | |
852 | } else | |
853 | brelse(bh); | |
854 | ||
855 | dblock++; | |
856 | extlen--; | |
857 | ||
858 | if (buffer_uptodate(first_bh)) | |
859 | break; | |
860 | } | |
861 | ||
862 | out: | |
863 | brelse(first_bh); | |
864 | } | |
865 | ||
866 | /** | |
867 | * gfs2_meta_syncfs - sync all the buffers in a filesystem | |
868 | * @sdp: the filesystem | |
869 | * | |
870 | */ | |
871 | ||
872 | void gfs2_meta_syncfs(struct gfs2_sbd *sdp) | |
873 | { | |
874 | gfs2_log_flush(sdp); | |
875 | for (;;) { | |
876 | gfs2_ail1_start(sdp, DIO_ALL); | |
877 | if (gfs2_ail1_empty(sdp, DIO_ALL)) | |
878 | break; | |
879 | msleep(100); | |
880 | } | |
881 | } | |
882 |