| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved. | 
| Steven Whitehouse | 3a8a9a1 | 2006-05-18 15:09:15 -0400 | [diff] [blame] | 3 |  * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved. | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 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 | 
| Steven Whitehouse | e9fc2aa | 2006-09-01 11:05:15 -0400 | [diff] [blame] | 7 |  * of the GNU General Public License version 2. | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 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> | 
| Steven Whitehouse | 2e565bb | 2006-10-02 11:38:25 -0400 | [diff] [blame] | 20 | #include <linux/bio.h> | 
| Steven Whitehouse | 5c676f6 | 2006-02-27 17:23:27 -0500 | [diff] [blame] | 21 | #include <linux/gfs2_ondisk.h> | 
| Fabio Massimo Di Nitto | 7d30859 | 2006-09-19 07:56:29 +0200 | [diff] [blame] | 22 | #include <linux/lm_interface.h> | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 23 |  | 
 | 24 | #include "gfs2.h" | 
| Steven Whitehouse | 5c676f6 | 2006-02-27 17:23:27 -0500 | [diff] [blame] | 25 | #include "incore.h" | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 26 | #include "glock.h" | 
 | 27 | #include "glops.h" | 
 | 28 | #include "inode.h" | 
 | 29 | #include "log.h" | 
 | 30 | #include "lops.h" | 
 | 31 | #include "meta_io.h" | 
 | 32 | #include "rgrp.h" | 
 | 33 | #include "trans.h" | 
| Steven Whitehouse | 5c676f6 | 2006-02-27 17:23:27 -0500 | [diff] [blame] | 34 | #include "util.h" | 
| Steven Whitehouse | 4340fe6 | 2006-07-11 09:46:33 -0400 | [diff] [blame] | 35 | #include "ops_address.h" | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 36 |  | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 37 | static int aspace_get_block(struct inode *inode, sector_t lblock, | 
 | 38 | 			    struct buffer_head *bh_result, int create) | 
 | 39 | { | 
| Steven Whitehouse | 5c676f6 | 2006-02-27 17:23:27 -0500 | [diff] [blame] | 40 | 	gfs2_assert_warn(inode->i_sb->s_fs_info, 0); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 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 |  | 
| Steven Whitehouse | 66de045 | 2006-07-03 13:37:30 -0400 | [diff] [blame] | 50 | static const struct address_space_operations aspace_aops = { | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 51 | 	.writepage = gfs2_aspace_writepage, | 
| Steven Whitehouse | 4340fe6 | 2006-07-11 09:46:33 -0400 | [diff] [blame] | 52 | 	.releasepage = gfs2_releasepage, | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 53 | }; | 
 | 54 |  | 
 | 55 | /** | 
 | 56 |  * gfs2_aspace_get - Create and initialize a struct inode structure | 
 | 57 |  * @sdp: the filesystem the aspace is in | 
 | 58 |  * | 
 | 59 |  * Right now a struct inode is just a struct inode.  Maybe Linux | 
 | 60 |  * will supply a more lightweight address space construct (that works) | 
 | 61 |  * in the future. | 
 | 62 |  * | 
 | 63 |  * Make sure pages/buffers in this aspace aren't in high memory. | 
 | 64 |  * | 
 | 65 |  * Returns: the aspace | 
 | 66 |  */ | 
 | 67 |  | 
 | 68 | struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp) | 
 | 69 | { | 
 | 70 | 	struct inode *aspace; | 
 | 71 |  | 
 | 72 | 	aspace = new_inode(sdp->sd_vfs); | 
 | 73 | 	if (aspace) { | 
| Steven Whitehouse | f3bba03 | 2006-07-11 09:50:54 -0400 | [diff] [blame] | 74 | 		mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 75 | 		aspace->i_mapping->a_ops = &aspace_aops; | 
 | 76 | 		aspace->i_size = ~0ULL; | 
| Theodore Ts'o | bba9dfd | 2006-09-27 01:50:31 -0700 | [diff] [blame] | 77 | 		aspace->i_private = NULL; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 78 | 		insert_inode_hash(aspace); | 
 | 79 | 	} | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 80 | 	return aspace; | 
 | 81 | } | 
 | 82 |  | 
 | 83 | void gfs2_aspace_put(struct inode *aspace) | 
 | 84 | { | 
 | 85 | 	remove_inode_hash(aspace); | 
 | 86 | 	iput(aspace); | 
 | 87 | } | 
 | 88 |  | 
 | 89 | /** | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 90 |  * gfs2_meta_inval - Invalidate all buffers associated with a glock | 
 | 91 |  * @gl: the glock | 
 | 92 |  * | 
 | 93 |  */ | 
 | 94 |  | 
 | 95 | void gfs2_meta_inval(struct gfs2_glock *gl) | 
 | 96 | { | 
 | 97 | 	struct gfs2_sbd *sdp = gl->gl_sbd; | 
 | 98 | 	struct inode *aspace = gl->gl_aspace; | 
 | 99 | 	struct address_space *mapping = gl->gl_aspace->i_mapping; | 
 | 100 |  | 
 | 101 | 	gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); | 
 | 102 |  | 
 | 103 | 	atomic_inc(&aspace->i_writecount); | 
 | 104 | 	truncate_inode_pages(mapping, 0); | 
 | 105 | 	atomic_dec(&aspace->i_writecount); | 
 | 106 |  | 
 | 107 | 	gfs2_assert_withdraw(sdp, !mapping->nrpages); | 
 | 108 | } | 
 | 109 |  | 
 | 110 | /** | 
 | 111 |  * gfs2_meta_sync - Sync all buffers associated with a glock | 
 | 112 |  * @gl: The glock | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 113 |  * | 
 | 114 |  */ | 
 | 115 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 116 | void gfs2_meta_sync(struct gfs2_glock *gl) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 117 | { | 
 | 118 | 	struct address_space *mapping = gl->gl_aspace->i_mapping; | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 119 | 	int error; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 120 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 121 | 	filemap_fdatawrite(mapping); | 
 | 122 | 	error = filemap_fdatawait(mapping); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 123 |  | 
 | 124 | 	if (error) | 
 | 125 | 		gfs2_io_error(gl->gl_sbd); | 
 | 126 | } | 
 | 127 |  | 
 | 128 | /** | 
 | 129 |  * getbuf - Get a buffer with a given address space | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 130 |  * @gl: the glock | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 131 |  * @blkno: the block number (filesystem scope) | 
 | 132 |  * @create: 1 if the buffer should be created | 
 | 133 |  * | 
 | 134 |  * Returns: the buffer | 
 | 135 |  */ | 
 | 136 |  | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 137 | static struct buffer_head *getbuf(struct gfs2_glock *gl, u64 blkno, int create) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 138 | { | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 139 | 	struct address_space *mapping = gl->gl_aspace->i_mapping; | 
 | 140 | 	struct gfs2_sbd *sdp = gl->gl_sbd; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 141 | 	struct page *page; | 
 | 142 | 	struct buffer_head *bh; | 
 | 143 | 	unsigned int shift; | 
 | 144 | 	unsigned long index; | 
 | 145 | 	unsigned int bufnum; | 
 | 146 |  | 
 | 147 | 	shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift; | 
 | 148 | 	index = blkno >> shift;             /* convert block to page */ | 
 | 149 | 	bufnum = blkno - (index << shift);  /* block buf index within page */ | 
 | 150 |  | 
 | 151 | 	if (create) { | 
 | 152 | 		for (;;) { | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 153 | 			page = grab_cache_page(mapping, index); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 154 | 			if (page) | 
 | 155 | 				break; | 
 | 156 | 			yield(); | 
 | 157 | 		} | 
 | 158 | 	} else { | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 159 | 		page = find_lock_page(mapping, index); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 160 | 		if (!page) | 
 | 161 | 			return NULL; | 
 | 162 | 	} | 
 | 163 |  | 
 | 164 | 	if (!page_has_buffers(page)) | 
 | 165 | 		create_empty_buffers(page, sdp->sd_sb.sb_bsize, 0); | 
 | 166 |  | 
 | 167 | 	/* Locate header for our buffer within our page */ | 
 | 168 | 	for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page) | 
 | 169 | 		/* Do nothing */; | 
 | 170 | 	get_bh(bh); | 
 | 171 |  | 
 | 172 | 	if (!buffer_mapped(bh)) | 
 | 173 | 		map_bh(bh, sdp->sd_vfs, blkno); | 
 | 174 |  | 
 | 175 | 	unlock_page(page); | 
 | 176 | 	mark_page_accessed(page); | 
 | 177 | 	page_cache_release(page); | 
 | 178 |  | 
 | 179 | 	return bh; | 
 | 180 | } | 
 | 181 |  | 
 | 182 | static void meta_prep_new(struct buffer_head *bh) | 
 | 183 | { | 
 | 184 | 	struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; | 
 | 185 |  | 
 | 186 | 	lock_buffer(bh); | 
 | 187 | 	clear_buffer_dirty(bh); | 
 | 188 | 	set_buffer_uptodate(bh); | 
 | 189 | 	unlock_buffer(bh); | 
 | 190 |  | 
 | 191 | 	mh->mh_magic = cpu_to_be32(GFS2_MAGIC); | 
 | 192 | } | 
 | 193 |  | 
 | 194 | /** | 
 | 195 |  * gfs2_meta_new - Get a block | 
 | 196 |  * @gl: The glock associated with this block | 
 | 197 |  * @blkno: The block number | 
 | 198 |  * | 
 | 199 |  * Returns: The buffer | 
 | 200 |  */ | 
 | 201 |  | 
| Steven Whitehouse | cd91549 | 2006-09-04 12:49:07 -0400 | [diff] [blame] | 202 | struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 203 | { | 
 | 204 | 	struct buffer_head *bh; | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 205 | 	bh = getbuf(gl, blkno, CREATE); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 206 | 	meta_prep_new(bh); | 
 | 207 | 	return bh; | 
 | 208 | } | 
 | 209 |  | 
 | 210 | /** | 
 | 211 |  * gfs2_meta_read - Read a block from disk | 
 | 212 |  * @gl: The glock covering the block | 
 | 213 |  * @blkno: The block number | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 214 |  * @flags: flags | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 215 |  * @bhp: the place where the buffer is returned (NULL on failure) | 
 | 216 |  * | 
 | 217 |  * Returns: errno | 
 | 218 |  */ | 
 | 219 |  | 
| Steven Whitehouse | cd91549 | 2006-09-04 12:49:07 -0400 | [diff] [blame] | 220 | int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 221 | 		   struct buffer_head **bhp) | 
 | 222 | { | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 223 | 	*bhp = getbuf(gl, blkno, CREATE); | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 224 | 	if (!buffer_uptodate(*bhp)) | 
| Steven Whitehouse | 2e565bb | 2006-10-02 11:38:25 -0400 | [diff] [blame] | 225 | 		ll_rw_block(READ_META, 1, bhp); | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 226 | 	if (flags & DIO_WAIT) { | 
 | 227 | 		int error = gfs2_meta_wait(gl->gl_sbd, *bhp); | 
 | 228 | 		if (error) { | 
 | 229 | 			brelse(*bhp); | 
 | 230 | 			return error; | 
 | 231 | 		} | 
 | 232 | 	} | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 233 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 234 | 	return 0; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 235 | } | 
 | 236 |  | 
 | 237 | /** | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 238 |  * gfs2_meta_wait - Reread a block from disk | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 239 |  * @sdp: the filesystem | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 240 |  * @bh: The block to wait for | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 241 |  * | 
 | 242 |  * Returns: errno | 
 | 243 |  */ | 
 | 244 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 245 | int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 246 | { | 
 | 247 | 	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | 
 | 248 | 		return -EIO; | 
 | 249 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 250 | 	wait_on_buffer(bh); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 251 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 252 | 	if (!buffer_uptodate(bh)) { | 
 | 253 | 		struct gfs2_trans *tr = current->journal_info; | 
 | 254 | 		if (tr && tr->tr_touched) | 
 | 255 | 			gfs2_io_error_bh(sdp, bh); | 
 | 256 | 		return -EIO; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 257 | 	} | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 258 | 	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | 
 | 259 | 		return -EIO; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 260 |  | 
 | 261 | 	return 0; | 
 | 262 | } | 
 | 263 |  | 
 | 264 | /** | 
| Steven Whitehouse | 586dfda | 2006-01-18 11:32:00 +0000 | [diff] [blame] | 265 |  * gfs2_attach_bufdata - attach a struct gfs2_bufdata structure to a buffer | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 266 |  * @gl: the glock the buffer belongs to | 
 | 267 |  * @bh: The buffer to be attached to | 
| Steven Whitehouse | 586dfda | 2006-01-18 11:32:00 +0000 | [diff] [blame] | 268 |  * @meta: Flag to indicate whether its metadata or not | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 269 |  */ | 
 | 270 |  | 
| Steven Whitehouse | 568f4c9 | 2006-02-27 12:00:42 -0500 | [diff] [blame] | 271 | void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, | 
 | 272 | 			 int meta) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 273 | { | 
 | 274 | 	struct gfs2_bufdata *bd; | 
 | 275 |  | 
| Steven Whitehouse | 18ec7d5 | 2006-02-08 11:50:51 +0000 | [diff] [blame] | 276 | 	if (meta) | 
 | 277 | 		lock_page(bh->b_page); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 278 |  | 
| Steven Whitehouse | 5c676f6 | 2006-02-27 17:23:27 -0500 | [diff] [blame] | 279 | 	if (bh->b_private) { | 
| Steven Whitehouse | 18ec7d5 | 2006-02-08 11:50:51 +0000 | [diff] [blame] | 280 | 		if (meta) | 
 | 281 | 			unlock_page(bh->b_page); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 282 | 		return; | 
 | 283 | 	} | 
 | 284 |  | 
| Robert P. J. Day | c376222 | 2007-02-10 01:45:03 -0800 | [diff] [blame] | 285 | 	bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL), | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 286 | 	bd->bd_bh = bh; | 
 | 287 | 	bd->bd_gl = gl; | 
 | 288 |  | 
 | 289 | 	INIT_LIST_HEAD(&bd->bd_list_tr); | 
| Steven Whitehouse | 82ffa51 | 2006-09-04 14:47:06 -0400 | [diff] [blame] | 290 | 	if (meta) | 
| Steven Whitehouse | 586dfda | 2006-01-18 11:32:00 +0000 | [diff] [blame] | 291 | 		lops_init_le(&bd->bd_le, &gfs2_buf_lops); | 
| Steven Whitehouse | 82ffa51 | 2006-09-04 14:47:06 -0400 | [diff] [blame] | 292 | 	else | 
| Steven Whitehouse | 586dfda | 2006-01-18 11:32:00 +0000 | [diff] [blame] | 293 | 		lops_init_le(&bd->bd_le, &gfs2_databuf_lops); | 
| Steven Whitehouse | 5c676f6 | 2006-02-27 17:23:27 -0500 | [diff] [blame] | 294 | 	bh->b_private = bd; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 295 |  | 
| Steven Whitehouse | 18ec7d5 | 2006-02-08 11:50:51 +0000 | [diff] [blame] | 296 | 	if (meta) | 
 | 297 | 		unlock_page(bh->b_page); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 298 | } | 
 | 299 |  | 
| Steven Whitehouse | 16615be | 2007-09-17 10:59:52 +0100 | [diff] [blame] | 300 | void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int meta) | 
 | 301 | { | 
 | 302 | 	struct gfs2_sbd *sdp = GFS2_SB(bh->b_page->mapping->host); | 
 | 303 | 	struct gfs2_bufdata *bd = bh->b_private; | 
 | 304 | 	if (test_clear_buffer_pinned(bh)) { | 
 | 305 | 		list_del_init(&bd->bd_le.le_list); | 
 | 306 | 		if (meta) { | 
 | 307 | 			gfs2_assert_warn(sdp, sdp->sd_log_num_buf); | 
 | 308 | 			sdp->sd_log_num_buf--; | 
 | 309 | 			tr->tr_num_buf_rm++; | 
 | 310 | 		} else { | 
 | 311 | 			gfs2_assert_warn(sdp, sdp->sd_log_num_databuf); | 
 | 312 | 			sdp->sd_log_num_databuf--; | 
 | 313 | 			tr->tr_num_databuf_rm++; | 
 | 314 | 		} | 
 | 315 | 		tr->tr_touched = 1; | 
 | 316 | 		brelse(bh); | 
 | 317 | 	} | 
 | 318 | 	if (bd) { | 
 | 319 | 		if (bd->bd_ail) { | 
 | 320 | 			gfs2_remove_from_ail(NULL, bd); | 
 | 321 | 			bh->b_private = NULL; | 
 | 322 | 			bd->bd_bh = NULL; | 
 | 323 | 			bd->bd_blkno = bh->b_blocknr; | 
 | 324 | 			gfs2_trans_add_revoke(sdp, bd); | 
 | 325 | 		} | 
 | 326 | 	} | 
 | 327 | 	clear_buffer_dirty(bh); | 
 | 328 | 	clear_buffer_uptodate(bh); | 
 | 329 | } | 
 | 330 |  | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 331 | /** | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 332 |  * gfs2_meta_wipe - make inode's buffers so they aren't dirty/pinned anymore | 
 | 333 |  * @ip: the inode who owns the buffers | 
 | 334 |  * @bstart: the first buffer in the run | 
 | 335 |  * @blen: the number of buffers in the run | 
 | 336 |  * | 
 | 337 |  */ | 
 | 338 |  | 
| Steven Whitehouse | cd91549 | 2006-09-04 12:49:07 -0400 | [diff] [blame] | 339 | void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 340 | { | 
| Steven Whitehouse | feaa7bb | 2006-06-14 15:32:57 -0400 | [diff] [blame] | 341 | 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 342 | 	struct buffer_head *bh; | 
 | 343 |  | 
 | 344 | 	while (blen) { | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 345 | 		bh = getbuf(ip->i_gl, bstart, NO_CREATE); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 346 | 		if (bh) { | 
| Steven Whitehouse | 1ad38c4 | 2007-09-03 11:01:33 +0100 | [diff] [blame] | 347 | 			lock_buffer(bh); | 
 | 348 | 			gfs2_log_lock(sdp); | 
| Steven Whitehouse | 16615be | 2007-09-17 10:59:52 +0100 | [diff] [blame] | 349 | 			gfs2_remove_from_journal(bh, current->journal_info, 1); | 
| Steven Whitehouse | 1ad38c4 | 2007-09-03 11:01:33 +0100 | [diff] [blame] | 350 | 			gfs2_log_unlock(sdp); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 351 | 			unlock_buffer(bh); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 352 | 			brelse(bh); | 
 | 353 | 		} | 
 | 354 |  | 
 | 355 | 		bstart++; | 
 | 356 | 		blen--; | 
 | 357 | 	} | 
 | 358 | } | 
 | 359 |  | 
 | 360 | /** | 
 | 361 |  * gfs2_meta_cache_flush - get rid of any references on buffers for this inode | 
 | 362 |  * @ip: The GFS2 inode | 
 | 363 |  * | 
 | 364 |  * This releases buffers that are in the most-recently-used array of | 
 | 365 |  * blocks used for indirect block addressing for this inode. | 
 | 366 |  */ | 
 | 367 |  | 
 | 368 | void gfs2_meta_cache_flush(struct gfs2_inode *ip) | 
 | 369 | { | 
 | 370 | 	struct buffer_head **bh_slot; | 
 | 371 | 	unsigned int x; | 
 | 372 |  | 
 | 373 | 	spin_lock(&ip->i_spin); | 
 | 374 |  | 
 | 375 | 	for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) { | 
 | 376 | 		bh_slot = &ip->i_cache[x]; | 
| Wendy Cheng | de986e8 | 2007-09-18 09:19:13 -0400 | [diff] [blame] | 377 | 		if (*bh_slot) { | 
 | 378 | 			brelse(*bh_slot); | 
 | 379 | 			*bh_slot = NULL; | 
 | 380 | 		} | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 381 | 	} | 
 | 382 |  | 
 | 383 | 	spin_unlock(&ip->i_spin); | 
 | 384 | } | 
 | 385 |  | 
 | 386 | /** | 
 | 387 |  * gfs2_meta_indirect_buffer - Get a metadata buffer | 
 | 388 |  * @ip: The GFS2 inode | 
 | 389 |  * @height: The level of this buf in the metadata (indir addr) tree (if any) | 
 | 390 |  * @num: The block number (device relative) of the buffer | 
 | 391 |  * @new: Non-zero if we may create a new buffer | 
 | 392 |  * @bhp: the buffer is returned here | 
 | 393 |  * | 
 | 394 |  * Try to use the gfs2_inode's MRU metadata tree cache. | 
 | 395 |  * | 
 | 396 |  * Returns: errno | 
 | 397 |  */ | 
 | 398 |  | 
| Steven Whitehouse | cd91549 | 2006-09-04 12:49:07 -0400 | [diff] [blame] | 399 | int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 400 | 			      int new, struct buffer_head **bhp) | 
 | 401 | { | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 402 | 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 
 | 403 | 	struct gfs2_glock *gl = ip->i_gl; | 
 | 404 | 	struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height; | 
 | 405 | 	int in_cache = 0; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 406 |  | 
| Steven Whitehouse | b004157 | 2006-11-23 10:51:34 -0500 | [diff] [blame] | 407 | 	BUG_ON(!gl); | 
 | 408 | 	BUG_ON(!sdp); | 
 | 409 |  | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 410 | 	spin_lock(&ip->i_spin); | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 411 | 	if (*bh_slot && (*bh_slot)->b_blocknr == num) { | 
 | 412 | 		bh = *bh_slot; | 
 | 413 | 		get_bh(bh); | 
 | 414 | 		in_cache = 1; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 415 | 	} | 
 | 416 | 	spin_unlock(&ip->i_spin); | 
 | 417 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 418 | 	if (!bh) | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 419 | 		bh = getbuf(gl, num, CREATE); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 420 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 421 | 	if (!bh) | 
 | 422 | 		return -ENOBUFS; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 423 |  | 
 | 424 | 	if (new) { | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 425 | 		if (gfs2_assert_warn(sdp, height)) | 
 | 426 | 			goto err; | 
 | 427 | 		meta_prep_new(bh); | 
| Steven Whitehouse | d4e9c4c | 2006-01-18 11:19:28 +0000 | [diff] [blame] | 428 | 		gfs2_trans_add_bh(ip->i_gl, bh, 1); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 429 | 		gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); | 
 | 430 | 		gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header)); | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 431 | 	} else { | 
 | 432 | 		u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI; | 
 | 433 | 		if (!buffer_uptodate(bh)) { | 
| Steven Whitehouse | 2e565bb | 2006-10-02 11:38:25 -0400 | [diff] [blame] | 434 | 			ll_rw_block(READ_META, 1, &bh); | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 435 | 			if (gfs2_meta_wait(sdp, bh)) | 
 | 436 | 				goto err; | 
 | 437 | 		} | 
 | 438 | 		if (gfs2_metatype_check(sdp, bh, mtype)) | 
 | 439 | 			goto err; | 
 | 440 | 	} | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 441 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 442 | 	if (!in_cache) { | 
 | 443 | 		spin_lock(&ip->i_spin); | 
 | 444 | 		if (*bh_slot) | 
 | 445 | 			brelse(*bh_slot); | 
 | 446 | 		*bh_slot = bh; | 
 | 447 | 		get_bh(bh); | 
 | 448 | 		spin_unlock(&ip->i_spin); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 449 | 	} | 
 | 450 |  | 
 | 451 | 	*bhp = bh; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 452 | 	return 0; | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 453 | err: | 
 | 454 | 	brelse(bh); | 
 | 455 | 	return -EIO; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 456 | } | 
 | 457 |  | 
 | 458 | /** | 
 | 459 |  * gfs2_meta_ra - start readahead on an extent of a file | 
 | 460 |  * @gl: the glock the blocks belong to | 
 | 461 |  * @dblock: the starting disk block | 
 | 462 |  * @extlen: the number of blocks in the extent | 
 | 463 |  * | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 464 |  * returns: the first buffer in the extent | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 465 |  */ | 
 | 466 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 467 | struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 468 | { | 
 | 469 | 	struct gfs2_sbd *sdp = gl->gl_sbd; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 470 | 	struct buffer_head *first_bh, *bh; | 
| Steven Whitehouse | cd91549 | 2006-09-04 12:49:07 -0400 | [diff] [blame] | 471 | 	u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> | 
| Steven Whitehouse | 568f4c9 | 2006-02-27 12:00:42 -0500 | [diff] [blame] | 472 | 			  sdp->sd_sb.sb_bsize_shift; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 473 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 474 | 	BUG_ON(!extlen); | 
 | 475 |  | 
 | 476 | 	if (max_ra < 1) | 
 | 477 | 		max_ra = 1; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 478 | 	if (extlen > max_ra) | 
 | 479 | 		extlen = max_ra; | 
 | 480 |  | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 481 | 	first_bh = getbuf(gl, dblock, CREATE); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 482 |  | 
 | 483 | 	if (buffer_uptodate(first_bh)) | 
 | 484 | 		goto out; | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 485 | 	if (!buffer_locked(first_bh)) | 
| Steven Whitehouse | 2e565bb | 2006-10-02 11:38:25 -0400 | [diff] [blame] | 486 | 		ll_rw_block(READ_META, 1, &first_bh); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 487 |  | 
 | 488 | 	dblock++; | 
 | 489 | 	extlen--; | 
 | 490 |  | 
 | 491 | 	while (extlen) { | 
| Steven Whitehouse | cb4c031 | 2006-11-23 11:16:32 -0500 | [diff] [blame] | 492 | 		bh = getbuf(gl, dblock, CREATE); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 493 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 494 | 		if (!buffer_uptodate(bh) && !buffer_locked(bh)) | 
 | 495 | 			ll_rw_block(READA, 1, &bh); | 
 | 496 | 		brelse(bh); | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 497 | 		dblock++; | 
 | 498 | 		extlen--; | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 499 | 		if (!buffer_locked(first_bh) && buffer_uptodate(first_bh)) | 
 | 500 | 			goto out; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 501 | 	} | 
 | 502 |  | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 503 | 	wait_on_buffer(first_bh); | 
| Steven Whitehouse | a91ea69 | 2006-09-04 12:04:26 -0400 | [diff] [blame] | 504 | out: | 
| Steven Whitehouse | 7276b3b | 2006-09-21 17:05:23 -0400 | [diff] [blame] | 505 | 	return first_bh; | 
| David Teigland | b3b94fa | 2006-01-16 16:50:04 +0000 | [diff] [blame] | 506 | } | 
 | 507 |  |