xref: /openbmc/linux/fs/gfs2/bmap.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
17336d0e6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b3b94faaSDavid Teigland /*
3b3b94faaSDavid Teigland  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
43a8a9a10SSteven Whitehouse  * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
5b3b94faaSDavid Teigland  */
6b3b94faaSDavid Teigland 
7b3b94faaSDavid Teigland #include <linux/spinlock.h>
8b3b94faaSDavid Teigland #include <linux/completion.h>
9b3b94faaSDavid Teigland #include <linux/buffer_head.h>
1064dd153cSBenjamin Marzinski #include <linux/blkdev.h>
115c676f6dSSteven Whitehouse #include <linux/gfs2_ondisk.h>
1271b86f56SSteven Whitehouse #include <linux/crc32.h>
133974320cSBob Peterson #include <linux/iomap.h>
1498583b3eSAbhi Das #include <linux/ktime.h>
15b3b94faaSDavid Teigland 
16b3b94faaSDavid Teigland #include "gfs2.h"
175c676f6dSSteven Whitehouse #include "incore.h"
18b3b94faaSDavid Teigland #include "bmap.h"
19b3b94faaSDavid Teigland #include "glock.h"
20b3b94faaSDavid Teigland #include "inode.h"
21b3b94faaSDavid Teigland #include "meta_io.h"
22b3b94faaSDavid Teigland #include "quota.h"
23b3b94faaSDavid Teigland #include "rgrp.h"
2445138990SSteven Whitehouse #include "log.h"
254c16c36aSBob Peterson #include "super.h"
26b3b94faaSDavid Teigland #include "trans.h"
2718ec7d5cSSteven Whitehouse #include "dir.h"
285c676f6dSSteven Whitehouse #include "util.h"
2964bc06bbSAndreas Gruenbacher #include "aops.h"
3063997775SSteven Whitehouse #include "trace_gfs2.h"
31b3b94faaSDavid Teigland 
32b3b94faaSDavid Teigland /* This doesn't need to be that large as max 64 bit pointers in a 4k
33b3b94faaSDavid Teigland  * block is 512, so __u16 is fine for that. It saves stack space to
34b3b94faaSDavid Teigland  * keep it small.
35b3b94faaSDavid Teigland  */
36b3b94faaSDavid Teigland struct metapath {
37dbac6710SSteven Whitehouse 	struct buffer_head *mp_bh[GFS2_MAX_META_HEIGHT];
38b3b94faaSDavid Teigland 	__u16 mp_list[GFS2_MAX_META_HEIGHT];
395f8bd444SBob Peterson 	int mp_fheight; /* find_metapath height */
405f8bd444SBob Peterson 	int mp_aheight; /* actual height (lookup height) */
41b3b94faaSDavid Teigland };
42b3b94faaSDavid Teigland 
4364bc06bbSAndreas Gruenbacher static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length);
4464bc06bbSAndreas Gruenbacher 
45b3b94faaSDavid Teigland /**
46f25ef0c1SSteven Whitehouse  * gfs2_unstuffer_page - unstuff a stuffed inode into a block cached by a page
47f25ef0c1SSteven Whitehouse  * @ip: the inode
48f25ef0c1SSteven Whitehouse  * @dibh: the dinode buffer
49f25ef0c1SSteven Whitehouse  * @block: the block number that was allocated
50ff8f33c8SSteven Whitehouse  * @page: The (optional) page. This is looked up if @page is NULL
51f25ef0c1SSteven Whitehouse  *
52f25ef0c1SSteven Whitehouse  * Returns: errno
53f25ef0c1SSteven Whitehouse  */
54f25ef0c1SSteven Whitehouse 
gfs2_unstuffer_page(struct gfs2_inode * ip,struct buffer_head * dibh,u64 block,struct page * page)55f25ef0c1SSteven Whitehouse static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
56cd915493SSteven Whitehouse 			       u64 block, struct page *page)
57f25ef0c1SSteven Whitehouse {
58f25ef0c1SSteven Whitehouse 	struct inode *inode = &ip->i_inode;
59f25ef0c1SSteven Whitehouse 
60f25ef0c1SSteven Whitehouse 	if (!PageUptodate(page)) {
61f25ef0c1SSteven Whitehouse 		void *kaddr = kmap(page);
62602c89d2SSteven Whitehouse 		u64 dsize = i_size_read(inode);
63f25ef0c1SSteven Whitehouse 
64602c89d2SSteven Whitehouse 		memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
6509cbfeafSKirill A. Shutemov 		memset(kaddr + dsize, 0, PAGE_SIZE - dsize);
66f25ef0c1SSteven Whitehouse 		kunmap(page);
67f25ef0c1SSteven Whitehouse 
68f25ef0c1SSteven Whitehouse 		SetPageUptodate(page);
69f25ef0c1SSteven Whitehouse 	}
70f25ef0c1SSteven Whitehouse 
712164f9b9SChristoph Hellwig 	if (gfs2_is_jdata(ip)) {
722164f9b9SChristoph Hellwig 		struct buffer_head *bh;
732164f9b9SChristoph Hellwig 
74f25ef0c1SSteven Whitehouse 		if (!page_has_buffers(page))
7547a9a527SFabian Frederick 			create_empty_buffers(page, BIT(inode->i_blkbits),
7647a9a527SFabian Frederick 					     BIT(BH_Uptodate));
77f25ef0c1SSteven Whitehouse 
78f25ef0c1SSteven Whitehouse 		bh = page_buffers(page);
79f25ef0c1SSteven Whitehouse 		if (!buffer_mapped(bh))
80f25ef0c1SSteven Whitehouse 			map_bh(bh, inode->i_sb, block);
81f25ef0c1SSteven Whitehouse 
82f25ef0c1SSteven Whitehouse 		set_buffer_uptodate(bh);
83350a9b0aSSteven Whitehouse 		gfs2_trans_add_data(ip->i_gl, bh);
842164f9b9SChristoph Hellwig 	} else {
852164f9b9SChristoph Hellwig 		set_page_dirty(page);
86845802b1SAndreas Gruenbacher 		gfs2_ordered_add_inode(ip);
87845802b1SAndreas Gruenbacher 	}
88f25ef0c1SSteven Whitehouse 
89f25ef0c1SSteven Whitehouse 	return 0;
90f25ef0c1SSteven Whitehouse }
91f25ef0c1SSteven Whitehouse 
__gfs2_unstuff_inode(struct gfs2_inode * ip,struct page * page)927a607a41SAndreas Gruenbacher static int __gfs2_unstuff_inode(struct gfs2_inode *ip, struct page *page)
93b3b94faaSDavid Teigland {
94b3b94faaSDavid Teigland 	struct buffer_head *bh, *dibh;
9548516cedSSteven Whitehouse 	struct gfs2_dinode *di;
96cd915493SSteven Whitehouse 	u64 block = 0;
9718ec7d5cSSteven Whitehouse 	int isdir = gfs2_is_dir(ip);
98b3b94faaSDavid Teigland 	int error;
99b3b94faaSDavid Teigland 
100b3b94faaSDavid Teigland 	error = gfs2_meta_inode_buffer(ip, &dibh);
101b3b94faaSDavid Teigland 	if (error)
1027a607a41SAndreas Gruenbacher 		return error;
103b3b94faaSDavid Teigland 
104a2e0f799SSteven Whitehouse 	if (i_size_read(&ip->i_inode)) {
105b3b94faaSDavid Teigland 		/* Get a free block, fill it with the stuffed data,
106b3b94faaSDavid Teigland 		   and write it out to disk */
107b3b94faaSDavid Teigland 
108b45e41d7SSteven Whitehouse 		unsigned int n = 1;
109*d92445b2SAndreas Gruenbacher 		error = gfs2_alloc_blocks(ip, &block, &n, 0);
11009010978SSteven Whitehouse 		if (error)
11109010978SSteven Whitehouse 			goto out_brelse;
11218ec7d5cSSteven Whitehouse 		if (isdir) {
113fbb27873SAndreas Gruenbacher 			gfs2_trans_remove_revoke(GFS2_SB(&ip->i_inode), block, 1);
11461e085a8SSteven Whitehouse 			error = gfs2_dir_get_new_buffer(ip, block, &bh);
115b3b94faaSDavid Teigland 			if (error)
116b3b94faaSDavid Teigland 				goto out_brelse;
11748516cedSSteven Whitehouse 			gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_meta_header),
118b3b94faaSDavid Teigland 					      dibh, sizeof(struct gfs2_dinode));
119b3b94faaSDavid Teigland 			brelse(bh);
120b3b94faaSDavid Teigland 		} else {
121f25ef0c1SSteven Whitehouse 			error = gfs2_unstuffer_page(ip, dibh, block, page);
122b3b94faaSDavid Teigland 			if (error)
123b3b94faaSDavid Teigland 				goto out_brelse;
124b3b94faaSDavid Teigland 		}
125b3b94faaSDavid Teigland 	}
126b3b94faaSDavid Teigland 
127b3b94faaSDavid Teigland 	/*  Set up the pointer to the new block  */
128b3b94faaSDavid Teigland 
129350a9b0aSSteven Whitehouse 	gfs2_trans_add_meta(ip->i_gl, dibh);
13048516cedSSteven Whitehouse 	di = (struct gfs2_dinode *)dibh->b_data;
131b3b94faaSDavid Teigland 	gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
132b3b94faaSDavid Teigland 
133a2e0f799SSteven Whitehouse 	if (i_size_read(&ip->i_inode)) {
13448516cedSSteven Whitehouse 		*(__be64 *)(di + 1) = cpu_to_be64(block);
13577658aadSSteven Whitehouse 		gfs2_add_inode_blocks(&ip->i_inode, 1);
13677658aadSSteven Whitehouse 		di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode));
137b3b94faaSDavid Teigland 	}
138b3b94faaSDavid Teigland 
139ecc30c79SSteven Whitehouse 	ip->i_height = 1;
14048516cedSSteven Whitehouse 	di->di_height = cpu_to_be16(1);
141b3b94faaSDavid Teigland 
142b3b94faaSDavid Teigland out_brelse:
143b3b94faaSDavid Teigland 	brelse(dibh);
1447a607a41SAndreas Gruenbacher 	return error;
1457a607a41SAndreas Gruenbacher }
1467a607a41SAndreas Gruenbacher 
1477a607a41SAndreas Gruenbacher /**
1487a607a41SAndreas Gruenbacher  * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big
1497a607a41SAndreas Gruenbacher  * @ip: The GFS2 inode to unstuff
1507a607a41SAndreas Gruenbacher  *
1517a607a41SAndreas Gruenbacher  * This routine unstuffs a dinode and returns it to a "normal" state such
1527a607a41SAndreas Gruenbacher  * that the height can be grown in the traditional way.
1537a607a41SAndreas Gruenbacher  *
1547a607a41SAndreas Gruenbacher  * Returns: errno
1557a607a41SAndreas Gruenbacher  */
1567a607a41SAndreas Gruenbacher 
gfs2_unstuff_dinode(struct gfs2_inode * ip)1577a607a41SAndreas Gruenbacher int gfs2_unstuff_dinode(struct gfs2_inode *ip)
1587a607a41SAndreas Gruenbacher {
1597a607a41SAndreas Gruenbacher 	struct inode *inode = &ip->i_inode;
1607a607a41SAndreas Gruenbacher 	struct page *page;
1617a607a41SAndreas Gruenbacher 	int error;
1627a607a41SAndreas Gruenbacher 
1637a607a41SAndreas Gruenbacher 	down_write(&ip->i_rw_mutex);
164dc0b9435SAndreas Gruenbacher 	page = grab_cache_page(inode->i_mapping, 0);
1657a607a41SAndreas Gruenbacher 	error = -ENOMEM;
1667a607a41SAndreas Gruenbacher 	if (!page)
1677a607a41SAndreas Gruenbacher 		goto out;
1687a607a41SAndreas Gruenbacher 	error = __gfs2_unstuff_inode(ip, page);
1697a607a41SAndreas Gruenbacher 	unlock_page(page);
1707a607a41SAndreas Gruenbacher 	put_page(page);
171b3b94faaSDavid Teigland out:
172b3b94faaSDavid Teigland 	up_write(&ip->i_rw_mutex);
173b3b94faaSDavid Teigland 	return error;
174b3b94faaSDavid Teigland }
175b3b94faaSDavid Teigland 
176b3b94faaSDavid Teigland /**
177b3b94faaSDavid Teigland  * find_metapath - Find path through the metadata tree
1789b8c81d1SSteven Whitehouse  * @sdp: The superblock
179b3b94faaSDavid Teigland  * @block: The disk block to look up
18007e23d68SAndreas Gruenbacher  * @mp: The metapath to return the result in
1819b8c81d1SSteven Whitehouse  * @height: The pre-calculated height of the metadata tree
182b3b94faaSDavid Teigland  *
183b3b94faaSDavid Teigland  *   This routine returns a struct metapath structure that defines a path
184b3b94faaSDavid Teigland  *   through the metadata of inode "ip" to get to block "block".
185b3b94faaSDavid Teigland  *
186b3b94faaSDavid Teigland  *   Example:
187b3b94faaSDavid Teigland  *   Given:  "ip" is a height 3 file, "offset" is 101342453, and this is a
188b3b94faaSDavid Teigland  *   filesystem with a blocksize of 4096.
189b3b94faaSDavid Teigland  *
190b3b94faaSDavid Teigland  *   find_metapath() would return a struct metapath structure set to:
19107e23d68SAndreas Gruenbacher  *   mp_fheight = 3, mp_list[0] = 0, mp_list[1] = 48, and mp_list[2] = 165.
192b3b94faaSDavid Teigland  *
193b3b94faaSDavid Teigland  *   That means that in order to get to the block containing the byte at
194b3b94faaSDavid Teigland  *   offset 101342453, we would load the indirect block pointed to by pointer
195b3b94faaSDavid Teigland  *   0 in the dinode.  We would then load the indirect block pointed to by
196b3b94faaSDavid Teigland  *   pointer 48 in that indirect block.  We would then load the data block
197b3b94faaSDavid Teigland  *   pointed to by pointer 165 in that indirect block.
198b3b94faaSDavid Teigland  *
199b3b94faaSDavid Teigland  *             ----------------------------------------
200b3b94faaSDavid Teigland  *             | Dinode |                             |
201b3b94faaSDavid Teigland  *             |        |                            4|
202b3b94faaSDavid Teigland  *             |        |0 1 2 3 4 5                 9|
203b3b94faaSDavid Teigland  *             |        |                            6|
204b3b94faaSDavid Teigland  *             ----------------------------------------
205b3b94faaSDavid Teigland  *                       |
206b3b94faaSDavid Teigland  *                       |
207b3b94faaSDavid Teigland  *                       V
208b3b94faaSDavid Teigland  *             ----------------------------------------
209b3b94faaSDavid Teigland  *             | Indirect Block                       |
210b3b94faaSDavid Teigland  *             |                                     5|
211b3b94faaSDavid Teigland  *             |            4 4 4 4 4 5 5            1|
212b3b94faaSDavid Teigland  *             |0           5 6 7 8 9 0 1            2|
213b3b94faaSDavid Teigland  *             ----------------------------------------
214b3b94faaSDavid Teigland  *                                |
215b3b94faaSDavid Teigland  *                                |
216b3b94faaSDavid Teigland  *                                V
217b3b94faaSDavid Teigland  *             ----------------------------------------
218b3b94faaSDavid Teigland  *             | Indirect Block                       |
219b3b94faaSDavid Teigland  *             |                         1 1 1 1 1   5|
220b3b94faaSDavid Teigland  *             |                         6 6 6 6 6   1|
221b3b94faaSDavid Teigland  *             |0                        3 4 5 6 7   2|
222b3b94faaSDavid Teigland  *             ----------------------------------------
223b3b94faaSDavid Teigland  *                                           |
224b3b94faaSDavid Teigland  *                                           |
225b3b94faaSDavid Teigland  *                                           V
226b3b94faaSDavid Teigland  *             ----------------------------------------
227b3b94faaSDavid Teigland  *             | Data block containing offset         |
228b3b94faaSDavid Teigland  *             |            101342453                 |
229b3b94faaSDavid Teigland  *             |                                      |
230b3b94faaSDavid Teigland  *             |                                      |
231b3b94faaSDavid Teigland  *             ----------------------------------------
232b3b94faaSDavid Teigland  *
233b3b94faaSDavid Teigland  */
234b3b94faaSDavid Teigland 
find_metapath(const struct gfs2_sbd * sdp,u64 block,struct metapath * mp,unsigned int height)2359b8c81d1SSteven Whitehouse static void find_metapath(const struct gfs2_sbd *sdp, u64 block,
2369b8c81d1SSteven Whitehouse 			  struct metapath *mp, unsigned int height)
237b3b94faaSDavid Teigland {
238b3b94faaSDavid Teigland 	unsigned int i;
239b3b94faaSDavid Teigland 
2405f8bd444SBob Peterson 	mp->mp_fheight = height;
2419b8c81d1SSteven Whitehouse 	for (i = height; i--;)
2427eabb77eSBob Peterson 		mp->mp_list[i] = do_div(block, sdp->sd_inptrs);
243b3b94faaSDavid Teigland }
244b3b94faaSDavid Teigland 
metapath_branch_start(const struct metapath * mp)2455af4e7a0SBenjamin Marzinski static inline unsigned int metapath_branch_start(const struct metapath *mp)
2469b8c81d1SSteven Whitehouse {
2475af4e7a0SBenjamin Marzinski 	if (mp->mp_list[0] == 0)
2485af4e7a0SBenjamin Marzinski 		return 2;
2495af4e7a0SBenjamin Marzinski 	return 1;
2509b8c81d1SSteven Whitehouse }
2519b8c81d1SSteven Whitehouse 
252b3b94faaSDavid Teigland /**
25320cdc193SAndreas Gruenbacher  * metaptr1 - Return the first possible metadata pointer in a metapath buffer
254d552a2b9SBob Peterson  * @height: The metadata height (0 = dinode)
255d552a2b9SBob Peterson  * @mp: The metapath
256d552a2b9SBob Peterson  */
metaptr1(unsigned int height,const struct metapath * mp)257d552a2b9SBob Peterson static inline __be64 *metaptr1(unsigned int height, const struct metapath *mp)
258d552a2b9SBob Peterson {
259d552a2b9SBob Peterson 	struct buffer_head *bh = mp->mp_bh[height];
260d552a2b9SBob Peterson 	if (height == 0)
261d552a2b9SBob Peterson 		return ((__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)));
262d552a2b9SBob Peterson 	return ((__be64 *)(bh->b_data + sizeof(struct gfs2_meta_header)));
263d552a2b9SBob Peterson }
264d552a2b9SBob Peterson 
265d552a2b9SBob Peterson /**
266b3b94faaSDavid Teigland  * metapointer - Return pointer to start of metadata in a buffer
267b3b94faaSDavid Teigland  * @height: The metadata height (0 = dinode)
268b3b94faaSDavid Teigland  * @mp: The metapath
269b3b94faaSDavid Teigland  *
270b3b94faaSDavid Teigland  * Return a pointer to the block number of the next height of the metadata
271b3b94faaSDavid Teigland  * tree given a buffer containing the pointer to the current height of the
272b3b94faaSDavid Teigland  * metadata tree.
273b3b94faaSDavid Teigland  */
274b3b94faaSDavid Teigland 
metapointer(unsigned int height,const struct metapath * mp)2759b8c81d1SSteven Whitehouse static inline __be64 *metapointer(unsigned int height, const struct metapath *mp)
276b3b94faaSDavid Teigland {
277d552a2b9SBob Peterson 	__be64 *p = metaptr1(height, mp);
278d552a2b9SBob Peterson 	return p + mp->mp_list[height];
279b3b94faaSDavid Teigland }
280b3b94faaSDavid Teigland 
metaend(unsigned int height,const struct metapath * mp)2817841b9f0SAndreas Gruenbacher static inline const __be64 *metaend(unsigned int height, const struct metapath *mp)
2827841b9f0SAndreas Gruenbacher {
2837841b9f0SAndreas Gruenbacher 	const struct buffer_head *bh = mp->mp_bh[height];
2847841b9f0SAndreas Gruenbacher 	return (const __be64 *)(bh->b_data + bh->b_size);
2857841b9f0SAndreas Gruenbacher }
2867841b9f0SAndreas Gruenbacher 
clone_metapath(struct metapath * clone,struct metapath * mp)2877841b9f0SAndreas Gruenbacher static void clone_metapath(struct metapath *clone, struct metapath *mp)
2887841b9f0SAndreas Gruenbacher {
2897841b9f0SAndreas Gruenbacher 	unsigned int hgt;
2907841b9f0SAndreas Gruenbacher 
2917841b9f0SAndreas Gruenbacher 	*clone = *mp;
2927841b9f0SAndreas Gruenbacher 	for (hgt = 0; hgt < mp->mp_aheight; hgt++)
2937841b9f0SAndreas Gruenbacher 		get_bh(clone->mp_bh[hgt]);
2947841b9f0SAndreas Gruenbacher }
2957841b9f0SAndreas Gruenbacher 
gfs2_metapath_ra(struct gfs2_glock * gl,__be64 * start,__be64 * end)2965cf26b1eSAndreas Gruenbacher static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
297b99b98dcSSteven Whitehouse {
298b99b98dcSSteven Whitehouse 	const __be64 *t;
299b99b98dcSSteven Whitehouse 
3005cf26b1eSAndreas Gruenbacher 	for (t = start; t < end; t++) {
301c3ce5aa9SAndreas Gruenbacher 		struct buffer_head *rabh;
302c3ce5aa9SAndreas Gruenbacher 
303b99b98dcSSteven Whitehouse 		if (!*t)
304b99b98dcSSteven Whitehouse 			continue;
305b99b98dcSSteven Whitehouse 
306b99b98dcSSteven Whitehouse 		rabh = gfs2_getbuf(gl, be64_to_cpu(*t), CREATE);
307b99b98dcSSteven Whitehouse 		if (trylock_buffer(rabh)) {
308b99b98dcSSteven Whitehouse 			if (!buffer_uptodate(rabh)) {
309b99b98dcSSteven Whitehouse 				rabh->b_end_io = end_buffer_read_sync;
3101420c4a5SBart Van Assche 				submit_bh(REQ_OP_READ | REQ_RAHEAD | REQ_META |
3111420c4a5SBart Van Assche 					  REQ_PRIO, rabh);
312b99b98dcSSteven Whitehouse 				continue;
313b99b98dcSSteven Whitehouse 			}
314b99b98dcSSteven Whitehouse 			unlock_buffer(rabh);
315b99b98dcSSteven Whitehouse 		}
316b99b98dcSSteven Whitehouse 		brelse(rabh);
317b99b98dcSSteven Whitehouse 	}
318b99b98dcSSteven Whitehouse }
319b99b98dcSSteven Whitehouse 
__fillup_metapath(struct gfs2_inode * ip,struct metapath * mp,unsigned int x,unsigned int h)320e8b43fe0SAndreas Gruenbacher static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp,
321e8b43fe0SAndreas Gruenbacher 			     unsigned int x, unsigned int h)
322d552a2b9SBob Peterson {
323e8b43fe0SAndreas Gruenbacher 	for (; x < h; x++) {
324e8b43fe0SAndreas Gruenbacher 		__be64 *ptr = metapointer(x, mp);
325d552a2b9SBob Peterson 		u64 dblock = be64_to_cpu(*ptr);
326e8b43fe0SAndreas Gruenbacher 		int ret;
327d552a2b9SBob Peterson 
328d552a2b9SBob Peterson 		if (!dblock)
329e8b43fe0SAndreas Gruenbacher 			break;
3306d8da302SAndreas Gruenbacher 		ret = gfs2_meta_buffer(ip, GFS2_METATYPE_IN, dblock, &mp->mp_bh[x + 1]);
331e8b43fe0SAndreas Gruenbacher 		if (ret)
332e8b43fe0SAndreas Gruenbacher 			return ret;
333e8b43fe0SAndreas Gruenbacher 	}
334e8b43fe0SAndreas Gruenbacher 	mp->mp_aheight = x + 1;
335e8b43fe0SAndreas Gruenbacher 	return 0;
336d552a2b9SBob Peterson }
337d552a2b9SBob Peterson 
338d552a2b9SBob Peterson /**
3399b8c81d1SSteven Whitehouse  * lookup_metapath - Walk the metadata tree to a specific point
3409b8c81d1SSteven Whitehouse  * @ip: The inode
341b3b94faaSDavid Teigland  * @mp: The metapath
342b3b94faaSDavid Teigland  *
3439b8c81d1SSteven Whitehouse  * Assumes that the inode's buffer has already been looked up and
3449b8c81d1SSteven Whitehouse  * hooked onto mp->mp_bh[0] and that the metapath has been initialised
3459b8c81d1SSteven Whitehouse  * by find_metapath().
346b3b94faaSDavid Teigland  *
3479b8c81d1SSteven Whitehouse  * If this function encounters part of the tree which has not been
3489b8c81d1SSteven Whitehouse  * allocated, it returns the current height of the tree at the point
3499b8c81d1SSteven Whitehouse  * at which it found the unallocated block. Blocks which are found are
3509b8c81d1SSteven Whitehouse  * added to the mp->mp_bh[] list.
3519b8c81d1SSteven Whitehouse  *
352e8b43fe0SAndreas Gruenbacher  * Returns: error
353b3b94faaSDavid Teigland  */
354b3b94faaSDavid Teigland 
lookup_metapath(struct gfs2_inode * ip,struct metapath * mp)3559b8c81d1SSteven Whitehouse static int lookup_metapath(struct gfs2_inode *ip, struct metapath *mp)
356b3b94faaSDavid Teigland {
357e8b43fe0SAndreas Gruenbacher 	return __fillup_metapath(ip, mp, 0, ip->i_height - 1);
358dbac6710SSteven Whitehouse }
359dbac6710SSteven Whitehouse 
360d552a2b9SBob Peterson /**
361d552a2b9SBob Peterson  * fillup_metapath - fill up buffers for the metadata path to a specific height
362d552a2b9SBob Peterson  * @ip: The inode
363d552a2b9SBob Peterson  * @mp: The metapath
364d552a2b9SBob Peterson  * @h: The height to which it should be mapped
365d552a2b9SBob Peterson  *
366d552a2b9SBob Peterson  * Similar to lookup_metapath, but does lookups for a range of heights
367d552a2b9SBob Peterson  *
368c3ce5aa9SAndreas Gruenbacher  * Returns: error or the number of buffers filled
369d552a2b9SBob Peterson  */
370d552a2b9SBob Peterson 
fillup_metapath(struct gfs2_inode * ip,struct metapath * mp,int h)371d552a2b9SBob Peterson static int fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, int h)
372d552a2b9SBob Peterson {
373e8b43fe0SAndreas Gruenbacher 	unsigned int x = 0;
374c3ce5aa9SAndreas Gruenbacher 	int ret;
375d552a2b9SBob Peterson 
376d552a2b9SBob Peterson 	if (h) {
377d552a2b9SBob Peterson 		/* find the first buffer we need to look up. */
378e8b43fe0SAndreas Gruenbacher 		for (x = h - 1; x > 0; x--) {
379e8b43fe0SAndreas Gruenbacher 			if (mp->mp_bh[x])
380e8b43fe0SAndreas Gruenbacher 				break;
381d552a2b9SBob Peterson 		}
382d552a2b9SBob Peterson 	}
383c3ce5aa9SAndreas Gruenbacher 	ret = __fillup_metapath(ip, mp, x, h);
384c3ce5aa9SAndreas Gruenbacher 	if (ret)
385c3ce5aa9SAndreas Gruenbacher 		return ret;
386c3ce5aa9SAndreas Gruenbacher 	return mp->mp_aheight - x - 1;
387d552a2b9SBob Peterson }
388d552a2b9SBob Peterson 
metapath_to_block(struct gfs2_sbd * sdp,struct metapath * mp)389a27a0c9bSAndreas Gruenbacher static sector_t metapath_to_block(struct gfs2_sbd *sdp, struct metapath *mp)
390a27a0c9bSAndreas Gruenbacher {
391a27a0c9bSAndreas Gruenbacher 	sector_t factor = 1, block = 0;
392a27a0c9bSAndreas Gruenbacher 	int hgt;
393a27a0c9bSAndreas Gruenbacher 
394a27a0c9bSAndreas Gruenbacher 	for (hgt = mp->mp_fheight - 1; hgt >= 0; hgt--) {
395a27a0c9bSAndreas Gruenbacher 		if (hgt < mp->mp_aheight)
396a27a0c9bSAndreas Gruenbacher 			block += mp->mp_list[hgt] * factor;
397a27a0c9bSAndreas Gruenbacher 		factor *= sdp->sd_inptrs;
398a27a0c9bSAndreas Gruenbacher 	}
399a27a0c9bSAndreas Gruenbacher 	return block;
400a27a0c9bSAndreas Gruenbacher }
401a27a0c9bSAndreas Gruenbacher 
release_metapath(struct metapath * mp)40264bc06bbSAndreas Gruenbacher static void release_metapath(struct metapath *mp)
403dbac6710SSteven Whitehouse {
404dbac6710SSteven Whitehouse 	int i;
405dbac6710SSteven Whitehouse 
4069b8c81d1SSteven Whitehouse 	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
4079b8c81d1SSteven Whitehouse 		if (mp->mp_bh[i] == NULL)
4089b8c81d1SSteven Whitehouse 			break;
409dbac6710SSteven Whitehouse 		brelse(mp->mp_bh[i]);
41064bc06bbSAndreas Gruenbacher 		mp->mp_bh[i] = NULL;
41111707ea0SSteven Whitehouse 	}
4129b8c81d1SSteven Whitehouse }
41311707ea0SSteven Whitehouse 
41430cbf189SSteven Whitehouse /**
41530cbf189SSteven Whitehouse  * gfs2_extent_length - Returns length of an extent of blocks
416bcfe9413SAndreas Gruenbacher  * @bh: The metadata block
417bcfe9413SAndreas Gruenbacher  * @ptr: Current position in @bh
418bcfe9413SAndreas Gruenbacher  * @limit: Max extent length to return
41930cbf189SSteven Whitehouse  * @eob: Set to 1 if we hit "end of block"
42030cbf189SSteven Whitehouse  *
42130cbf189SSteven Whitehouse  * Returns: The length of the extent (minimum of one block)
42230cbf189SSteven Whitehouse  */
42330cbf189SSteven Whitehouse 
gfs2_extent_length(struct buffer_head * bh,__be64 * ptr,size_t limit,int * eob)424bcfe9413SAndreas Gruenbacher static inline unsigned int gfs2_extent_length(struct buffer_head *bh, __be64 *ptr, size_t limit, int *eob)
42530cbf189SSteven Whitehouse {
426bcfe9413SAndreas Gruenbacher 	const __be64 *end = (__be64 *)(bh->b_data + bh->b_size);
42730cbf189SSteven Whitehouse 	const __be64 *first = ptr;
42830cbf189SSteven Whitehouse 	u64 d = be64_to_cpu(*ptr);
42930cbf189SSteven Whitehouse 
43030cbf189SSteven Whitehouse 	*eob = 0;
43130cbf189SSteven Whitehouse 	do {
43230cbf189SSteven Whitehouse 		ptr++;
43330cbf189SSteven Whitehouse 		if (ptr >= end)
43430cbf189SSteven Whitehouse 			break;
43530cbf189SSteven Whitehouse 		d++;
43630cbf189SSteven Whitehouse 	} while(be64_to_cpu(*ptr) == d);
43730cbf189SSteven Whitehouse 	if (ptr >= end)
43830cbf189SSteven Whitehouse 		*eob = 1;
439bcfe9413SAndreas Gruenbacher 	return ptr - first;
44030cbf189SSteven Whitehouse }
44130cbf189SSteven Whitehouse 
442a27a0c9bSAndreas Gruenbacher enum walker_status { WALK_STOP, WALK_FOLLOW, WALK_CONTINUE };
4437841b9f0SAndreas Gruenbacher 
444a27a0c9bSAndreas Gruenbacher /*
445a27a0c9bSAndreas Gruenbacher  * gfs2_metadata_walker - walk an indirect block
446a27a0c9bSAndreas Gruenbacher  * @mp: Metapath to indirect block
447a27a0c9bSAndreas Gruenbacher  * @ptrs: Number of pointers to look at
448a27a0c9bSAndreas Gruenbacher  *
449a27a0c9bSAndreas Gruenbacher  * When returning WALK_FOLLOW, the walker must update @mp to point at the right
450a27a0c9bSAndreas Gruenbacher  * indirect block to follow.
451a27a0c9bSAndreas Gruenbacher  */
452a27a0c9bSAndreas Gruenbacher typedef enum walker_status (*gfs2_metadata_walker)(struct metapath *mp,
453a27a0c9bSAndreas Gruenbacher 						   unsigned int ptrs);
4547841b9f0SAndreas Gruenbacher 
455a27a0c9bSAndreas Gruenbacher /*
456a27a0c9bSAndreas Gruenbacher  * gfs2_walk_metadata - walk a tree of indirect blocks
457a27a0c9bSAndreas Gruenbacher  * @inode: The inode
458a27a0c9bSAndreas Gruenbacher  * @mp: Starting point of walk
459a27a0c9bSAndreas Gruenbacher  * @max_len: Maximum number of blocks to walk
460a27a0c9bSAndreas Gruenbacher  * @walker: Called during the walk
461a27a0c9bSAndreas Gruenbacher  *
462a27a0c9bSAndreas Gruenbacher  * Returns 1 if the walk was stopped by @walker, 0 if we went past @max_len or
463a27a0c9bSAndreas Gruenbacher  * past the end of metadata, and a negative error code otherwise.
464a27a0c9bSAndreas Gruenbacher  */
465a27a0c9bSAndreas Gruenbacher 
466a27a0c9bSAndreas Gruenbacher static int gfs2_walk_metadata(struct inode *inode, struct metapath *mp,
467a27a0c9bSAndreas Gruenbacher 		u64 max_len, gfs2_metadata_walker walker)
4687841b9f0SAndreas Gruenbacher {
4697841b9f0SAndreas Gruenbacher 	struct gfs2_inode *ip = GFS2_I(inode);
4707841b9f0SAndreas Gruenbacher 	struct gfs2_sbd *sdp = GFS2_SB(inode);
4717841b9f0SAndreas Gruenbacher 	u64 factor = 1;
4727841b9f0SAndreas Gruenbacher 	unsigned int hgt;
473a27a0c9bSAndreas Gruenbacher 	int ret;
4747841b9f0SAndreas Gruenbacher 
475a27a0c9bSAndreas Gruenbacher 	/*
476a27a0c9bSAndreas Gruenbacher 	 * The walk starts in the lowest allocated indirect block, which may be
477a27a0c9bSAndreas Gruenbacher 	 * before the position indicated by @mp.  Adjust @max_len accordingly
478a27a0c9bSAndreas Gruenbacher 	 * to avoid a short walk.
479a27a0c9bSAndreas Gruenbacher 	 */
480a27a0c9bSAndreas Gruenbacher 	for (hgt = mp->mp_fheight - 1; hgt >= mp->mp_aheight; hgt--) {
481a27a0c9bSAndreas Gruenbacher 		max_len += mp->mp_list[hgt] * factor;
482a27a0c9bSAndreas Gruenbacher 		mp->mp_list[hgt] = 0;
4837841b9f0SAndreas Gruenbacher 		factor *= sdp->sd_inptrs;
484a27a0c9bSAndreas Gruenbacher 	}
4857841b9f0SAndreas Gruenbacher 
4867841b9f0SAndreas Gruenbacher 	for (;;) {
487a27a0c9bSAndreas Gruenbacher 		u16 start = mp->mp_list[hgt];
488a27a0c9bSAndreas Gruenbacher 		enum walker_status status;
489a27a0c9bSAndreas Gruenbacher 		unsigned int ptrs;
490a27a0c9bSAndreas Gruenbacher 		u64 len;
4917841b9f0SAndreas Gruenbacher 
4927841b9f0SAndreas Gruenbacher 		/* Walk indirect block. */
493a27a0c9bSAndreas Gruenbacher 		ptrs = (hgt >= 1 ? sdp->sd_inptrs : sdp->sd_diptrs) - start;
494a27a0c9bSAndreas Gruenbacher 		len = ptrs * factor;
495a27a0c9bSAndreas Gruenbacher 		if (len > max_len)
496a27a0c9bSAndreas Gruenbacher 			ptrs = DIV_ROUND_UP_ULL(max_len, factor);
497a27a0c9bSAndreas Gruenbacher 		status = walker(mp, ptrs);
498a27a0c9bSAndreas Gruenbacher 		switch (status) {
499a27a0c9bSAndreas Gruenbacher 		case WALK_STOP:
500a27a0c9bSAndreas Gruenbacher 			return 1;
501a27a0c9bSAndreas Gruenbacher 		case WALK_FOLLOW:
502a27a0c9bSAndreas Gruenbacher 			BUG_ON(mp->mp_aheight == mp->mp_fheight);
503a27a0c9bSAndreas Gruenbacher 			ptrs = mp->mp_list[hgt] - start;
504a27a0c9bSAndreas Gruenbacher 			len = ptrs * factor;
5057841b9f0SAndreas Gruenbacher 			break;
506a27a0c9bSAndreas Gruenbacher 		case WALK_CONTINUE:
5077841b9f0SAndreas Gruenbacher 			break;
5087841b9f0SAndreas Gruenbacher 		}
509a27a0c9bSAndreas Gruenbacher 		if (len >= max_len)
510a27a0c9bSAndreas Gruenbacher 			break;
511a27a0c9bSAndreas Gruenbacher 		max_len -= len;
512a27a0c9bSAndreas Gruenbacher 		if (status == WALK_FOLLOW)
513a27a0c9bSAndreas Gruenbacher 			goto fill_up_metapath;
5147841b9f0SAndreas Gruenbacher 
5157841b9f0SAndreas Gruenbacher lower_metapath:
5167841b9f0SAndreas Gruenbacher 		/* Decrease height of metapath. */
5177841b9f0SAndreas Gruenbacher 		brelse(mp->mp_bh[hgt]);
5187841b9f0SAndreas Gruenbacher 		mp->mp_bh[hgt] = NULL;
519a27a0c9bSAndreas Gruenbacher 		mp->mp_list[hgt] = 0;
5207841b9f0SAndreas Gruenbacher 		if (!hgt)
5217841b9f0SAndreas Gruenbacher 			break;
5227841b9f0SAndreas Gruenbacher 		hgt--;
5237841b9f0SAndreas Gruenbacher 		factor *= sdp->sd_inptrs;
5247841b9f0SAndreas Gruenbacher 
5257841b9f0SAndreas Gruenbacher 		/* Advance in metadata tree. */
5267841b9f0SAndreas Gruenbacher 		(mp->mp_list[hgt])++;
527566a2ab3SAndreas Gruenbacher 		if (hgt) {
528566a2ab3SAndreas Gruenbacher 			if (mp->mp_list[hgt] >= sdp->sd_inptrs)
5297841b9f0SAndreas Gruenbacher 				goto lower_metapath;
530566a2ab3SAndreas Gruenbacher 		} else {
531566a2ab3SAndreas Gruenbacher 			if (mp->mp_list[hgt] >= sdp->sd_diptrs)
532566a2ab3SAndreas Gruenbacher 				break;
5337841b9f0SAndreas Gruenbacher 		}
5347841b9f0SAndreas Gruenbacher 
5357841b9f0SAndreas Gruenbacher fill_up_metapath:
5367841b9f0SAndreas Gruenbacher 		/* Increase height of metapath. */
5377841b9f0SAndreas Gruenbacher 		ret = fillup_metapath(ip, mp, ip->i_height - 1);
5387841b9f0SAndreas Gruenbacher 		if (ret < 0)
539a27a0c9bSAndreas Gruenbacher 			return ret;
5407841b9f0SAndreas Gruenbacher 		hgt += ret;
5417841b9f0SAndreas Gruenbacher 		for (; ret; ret--)
5427841b9f0SAndreas Gruenbacher 			do_div(factor, sdp->sd_inptrs);
5437841b9f0SAndreas Gruenbacher 		mp->mp_aheight = hgt + 1;
5447841b9f0SAndreas Gruenbacher 	}
545a27a0c9bSAndreas Gruenbacher 	return 0;
5467841b9f0SAndreas Gruenbacher }
5477841b9f0SAndreas Gruenbacher 
gfs2_hole_walker(struct metapath * mp,unsigned int ptrs)548a27a0c9bSAndreas Gruenbacher static enum walker_status gfs2_hole_walker(struct metapath *mp,
549a27a0c9bSAndreas Gruenbacher 					   unsigned int ptrs)
5507841b9f0SAndreas Gruenbacher {
551a27a0c9bSAndreas Gruenbacher 	const __be64 *start, *ptr, *end;
552a27a0c9bSAndreas Gruenbacher 	unsigned int hgt;
553a27a0c9bSAndreas Gruenbacher 
554a27a0c9bSAndreas Gruenbacher 	hgt = mp->mp_aheight - 1;
555a27a0c9bSAndreas Gruenbacher 	start = metapointer(hgt, mp);
556a27a0c9bSAndreas Gruenbacher 	end = start + ptrs;
5577841b9f0SAndreas Gruenbacher 
5587841b9f0SAndreas Gruenbacher 	for (ptr = start; ptr < end; ptr++) {
5597841b9f0SAndreas Gruenbacher 		if (*ptr) {
560a27a0c9bSAndreas Gruenbacher 			mp->mp_list[hgt] += ptr - start;
5617841b9f0SAndreas Gruenbacher 			if (mp->mp_aheight == mp->mp_fheight)
5627841b9f0SAndreas Gruenbacher 				return WALK_STOP;
563a27a0c9bSAndreas Gruenbacher 			return WALK_FOLLOW;
5647841b9f0SAndreas Gruenbacher 		}
5657841b9f0SAndreas Gruenbacher 	}
566a27a0c9bSAndreas Gruenbacher 	return WALK_CONTINUE;
5677841b9f0SAndreas Gruenbacher }
5687841b9f0SAndreas Gruenbacher 
5697841b9f0SAndreas Gruenbacher /**
5707841b9f0SAndreas Gruenbacher  * gfs2_hole_size - figure out the size of a hole
5717841b9f0SAndreas Gruenbacher  * @inode: The inode
5727841b9f0SAndreas Gruenbacher  * @lblock: The logical starting block number
5737841b9f0SAndreas Gruenbacher  * @len: How far to look (in blocks)
5747841b9f0SAndreas Gruenbacher  * @mp: The metapath at lblock
5757841b9f0SAndreas Gruenbacher  * @iomap: The iomap to store the hole size in
5767841b9f0SAndreas Gruenbacher  *
5777841b9f0SAndreas Gruenbacher  * This function modifies @mp.
5787841b9f0SAndreas Gruenbacher  *
5797841b9f0SAndreas Gruenbacher  * Returns: errno on error
5807841b9f0SAndreas Gruenbacher  */
gfs2_hole_size(struct inode * inode,sector_t lblock,u64 len,struct metapath * mp,struct iomap * iomap)5817841b9f0SAndreas Gruenbacher static int gfs2_hole_size(struct inode *inode, sector_t lblock, u64 len,
5827841b9f0SAndreas Gruenbacher 			  struct metapath *mp, struct iomap *iomap)
5837841b9f0SAndreas Gruenbacher {
584a27a0c9bSAndreas Gruenbacher 	struct metapath clone;
585a27a0c9bSAndreas Gruenbacher 	u64 hole_size;
586a27a0c9bSAndreas Gruenbacher 	int ret;
5877841b9f0SAndreas Gruenbacher 
588a27a0c9bSAndreas Gruenbacher 	clone_metapath(&clone, mp);
589a27a0c9bSAndreas Gruenbacher 	ret = gfs2_walk_metadata(inode, &clone, len, gfs2_hole_walker);
590a27a0c9bSAndreas Gruenbacher 	if (ret < 0)
591a27a0c9bSAndreas Gruenbacher 		goto out;
592a27a0c9bSAndreas Gruenbacher 
593a27a0c9bSAndreas Gruenbacher 	if (ret == 1)
594a27a0c9bSAndreas Gruenbacher 		hole_size = metapath_to_block(GFS2_SB(inode), &clone) - lblock;
595a27a0c9bSAndreas Gruenbacher 	else
596a27a0c9bSAndreas Gruenbacher 		hole_size = len;
597a27a0c9bSAndreas Gruenbacher 	iomap->length = hole_size << inode->i_blkbits;
598a27a0c9bSAndreas Gruenbacher 	ret = 0;
599a27a0c9bSAndreas Gruenbacher 
600a27a0c9bSAndreas Gruenbacher out:
601a27a0c9bSAndreas Gruenbacher 	release_metapath(&clone);
6027841b9f0SAndreas Gruenbacher 	return ret;
6037841b9f0SAndreas Gruenbacher }
6047841b9f0SAndreas Gruenbacher 
gfs2_indirect_init(struct metapath * mp,struct gfs2_glock * gl,unsigned int i,unsigned offset,u64 bn)605b2963932SBob Peterson static inline void gfs2_indirect_init(struct metapath *mp,
6069b8c81d1SSteven Whitehouse 				      struct gfs2_glock *gl, unsigned int i,
6079b8c81d1SSteven Whitehouse 				      unsigned offset, u64 bn)
6089b8c81d1SSteven Whitehouse {
6099b8c81d1SSteven Whitehouse 	__be64 *ptr = (__be64 *)(mp->mp_bh[i - 1]->b_data +
6109b8c81d1SSteven Whitehouse 		       ((i > 1) ? sizeof(struct gfs2_meta_header) :
6119b8c81d1SSteven Whitehouse 				 sizeof(struct gfs2_dinode)));
6129b8c81d1SSteven Whitehouse 	BUG_ON(i < 1);
6139b8c81d1SSteven Whitehouse 	BUG_ON(mp->mp_bh[i] != NULL);
6149b8c81d1SSteven Whitehouse 	mp->mp_bh[i] = gfs2_meta_new(gl, bn);
615350a9b0aSSteven Whitehouse 	gfs2_trans_add_meta(gl, mp->mp_bh[i]);
6169b8c81d1SSteven Whitehouse 	gfs2_metatype_set(mp->mp_bh[i], GFS2_METATYPE_IN, GFS2_FORMAT_IN);
6179b8c81d1SSteven Whitehouse 	gfs2_buffer_clear_tail(mp->mp_bh[i], sizeof(struct gfs2_meta_header));
6189b8c81d1SSteven Whitehouse 	ptr += offset;
6199b8c81d1SSteven Whitehouse 	*ptr = cpu_to_be64(bn);
6209b8c81d1SSteven Whitehouse }
6219b8c81d1SSteven Whitehouse 
6229b8c81d1SSteven Whitehouse enum alloc_state {
6239b8c81d1SSteven Whitehouse 	ALLOC_DATA = 0,
6249b8c81d1SSteven Whitehouse 	ALLOC_GROW_DEPTH = 1,
6259b8c81d1SSteven Whitehouse 	ALLOC_GROW_HEIGHT = 2,
6269b8c81d1SSteven Whitehouse 	/* ALLOC_UNSTUFF = 3,   TBD and rather complicated */
6279b8c81d1SSteven Whitehouse };
6289b8c81d1SSteven Whitehouse 
6299b8c81d1SSteven Whitehouse /**
63054992257SAndreas Gruenbacher  * __gfs2_iomap_alloc - Build a metadata tree of the requested height
6319b8c81d1SSteven Whitehouse  * @inode: The GFS2 inode
632628e366dSAndreas Gruenbacher  * @iomap: The iomap structure
6335f8bd444SBob Peterson  * @mp: The metapath, with proper height information calculated
6349b8c81d1SSteven Whitehouse  *
6359b8c81d1SSteven Whitehouse  * In this routine we may have to alloc:
6369b8c81d1SSteven Whitehouse  *   i) Indirect blocks to grow the metadata tree height
6379b8c81d1SSteven Whitehouse  *  ii) Indirect blocks to fill in lower part of the metadata tree
6389b8c81d1SSteven Whitehouse  * iii) Data blocks
6399b8c81d1SSteven Whitehouse  *
64054992257SAndreas Gruenbacher  * This function is called after __gfs2_iomap_get, which works out the
64164bc06bbSAndreas Gruenbacher  * total number of blocks which we need via gfs2_alloc_size.
64264bc06bbSAndreas Gruenbacher  *
64364bc06bbSAndreas Gruenbacher  * We then do the actual allocation asking for an extent at a time (if
64464bc06bbSAndreas Gruenbacher  * enough contiguous free blocks are available, there will only be one
64564bc06bbSAndreas Gruenbacher  * allocation request per call) and uses the state machine to initialise
64664bc06bbSAndreas Gruenbacher  * the blocks in order.
6479b8c81d1SSteven Whitehouse  *
648628e366dSAndreas Gruenbacher  * Right now, this function will allocate at most one indirect block
649628e366dSAndreas Gruenbacher  * worth of data -- with a default block size of 4K, that's slightly
650628e366dSAndreas Gruenbacher  * less than 2M.  If this limitation is ever removed to allow huge
651628e366dSAndreas Gruenbacher  * allocations, we would probably still want to limit the iomap size we
652628e366dSAndreas Gruenbacher  * return to avoid stalling other tasks during huge writes; the next
653628e366dSAndreas Gruenbacher  * iomap iteration would then find the blocks already allocated.
654628e366dSAndreas Gruenbacher  *
6559b8c81d1SSteven Whitehouse  * Returns: errno on error
6569b8c81d1SSteven Whitehouse  */
6579b8c81d1SSteven Whitehouse 
__gfs2_iomap_alloc(struct inode * inode,struct iomap * iomap,struct metapath * mp)65854992257SAndreas Gruenbacher static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
659bb4cb25dSAndreas Gruenbacher 			      struct metapath *mp)
6609b8c81d1SSteven Whitehouse {
6619b8c81d1SSteven Whitehouse 	struct gfs2_inode *ip = GFS2_I(inode);
6629b8c81d1SSteven Whitehouse 	struct gfs2_sbd *sdp = GFS2_SB(inode);
6639b8c81d1SSteven Whitehouse 	struct buffer_head *dibh = mp->mp_bh[0];
6645f8bd444SBob Peterson 	u64 bn;
6655af4e7a0SBenjamin Marzinski 	unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
66664bc06bbSAndreas Gruenbacher 	size_t dblks = iomap->length >> inode->i_blkbits;
6675f8bd444SBob Peterson 	const unsigned end_of_metadata = mp->mp_fheight - 1;
668628e366dSAndreas Gruenbacher 	int ret;
6699b8c81d1SSteven Whitehouse 	enum alloc_state state;
6709b8c81d1SSteven Whitehouse 	__be64 *ptr;
6719b8c81d1SSteven Whitehouse 	__be64 zero_bn = 0;
6729b8c81d1SSteven Whitehouse 
6735f8bd444SBob Peterson 	BUG_ON(mp->mp_aheight < 1);
6749b8c81d1SSteven Whitehouse 	BUG_ON(dibh == NULL);
67564bc06bbSAndreas Gruenbacher 	BUG_ON(dblks < 1);
6769b8c81d1SSteven Whitehouse 
677350a9b0aSSteven Whitehouse 	gfs2_trans_add_meta(ip->i_gl, dibh);
6789b8c81d1SSteven Whitehouse 
679628e366dSAndreas Gruenbacher 	down_write(&ip->i_rw_mutex);
680628e366dSAndreas Gruenbacher 
6815f8bd444SBob Peterson 	if (mp->mp_fheight == mp->mp_aheight) {
68264bc06bbSAndreas Gruenbacher 		/* Bottom indirect block exists */
6839b8c81d1SSteven Whitehouse 		state = ALLOC_DATA;
6849b8c81d1SSteven Whitehouse 	} else {
6859b8c81d1SSteven Whitehouse 		/* Need to allocate indirect blocks */
6865f8bd444SBob Peterson 		if (mp->mp_fheight == ip->i_height) {
6879b8c81d1SSteven Whitehouse 			/* Writing into existing tree, extend tree down */
6885f8bd444SBob Peterson 			iblks = mp->mp_fheight - mp->mp_aheight;
6899b8c81d1SSteven Whitehouse 			state = ALLOC_GROW_DEPTH;
6909b8c81d1SSteven Whitehouse 		} else {
6919b8c81d1SSteven Whitehouse 			/* Building up tree height */
6929b8c81d1SSteven Whitehouse 			state = ALLOC_GROW_HEIGHT;
6935f8bd444SBob Peterson 			iblks = mp->mp_fheight - ip->i_height;
6945af4e7a0SBenjamin Marzinski 			branch_start = metapath_branch_start(mp);
6955f8bd444SBob Peterson 			iblks += (mp->mp_fheight - branch_start);
6969b8c81d1SSteven Whitehouse 		}
6979b8c81d1SSteven Whitehouse 	}
6989b8c81d1SSteven Whitehouse 
6999b8c81d1SSteven Whitehouse 	/* start of the second part of the function (state machine) */
7009b8c81d1SSteven Whitehouse 
7013974320cSBob Peterson 	blks = dblks + iblks;
7025f8bd444SBob Peterson 	i = mp->mp_aheight;
7039b8c81d1SSteven Whitehouse 	do {
7049b8c81d1SSteven Whitehouse 		n = blks - alloced;
705*d92445b2SAndreas Gruenbacher 		ret = gfs2_alloc_blocks(ip, &bn, &n, 0);
706628e366dSAndreas Gruenbacher 		if (ret)
707628e366dSAndreas Gruenbacher 			goto out;
7089b8c81d1SSteven Whitehouse 		alloced += n;
7099b8c81d1SSteven Whitehouse 		if (state != ALLOC_DATA || gfs2_is_jdata(ip))
710fbb27873SAndreas Gruenbacher 			gfs2_trans_remove_revoke(sdp, bn, n);
7119b8c81d1SSteven Whitehouse 		switch (state) {
7129b8c81d1SSteven Whitehouse 		/* Growing height of tree */
7139b8c81d1SSteven Whitehouse 		case ALLOC_GROW_HEIGHT:
7149b8c81d1SSteven Whitehouse 			if (i == 1) {
7159b8c81d1SSteven Whitehouse 				ptr = (__be64 *)(dibh->b_data +
7169b8c81d1SSteven Whitehouse 						 sizeof(struct gfs2_dinode));
7179b8c81d1SSteven Whitehouse 				zero_bn = *ptr;
7189b8c81d1SSteven Whitehouse 			}
7195f8bd444SBob Peterson 			for (; i - 1 < mp->mp_fheight - ip->i_height && n > 0;
7205f8bd444SBob Peterson 			     i++, n--)
7219b8c81d1SSteven Whitehouse 				gfs2_indirect_init(mp, ip->i_gl, i, 0, bn++);
7225f8bd444SBob Peterson 			if (i - 1 == mp->mp_fheight - ip->i_height) {
7239b8c81d1SSteven Whitehouse 				i--;
7249b8c81d1SSteven Whitehouse 				gfs2_buffer_copy_tail(mp->mp_bh[i],
7259b8c81d1SSteven Whitehouse 						sizeof(struct gfs2_meta_header),
7269b8c81d1SSteven Whitehouse 						dibh, sizeof(struct gfs2_dinode));
7279b8c81d1SSteven Whitehouse 				gfs2_buffer_clear_tail(dibh,
7289b8c81d1SSteven Whitehouse 						sizeof(struct gfs2_dinode) +
7299b8c81d1SSteven Whitehouse 						sizeof(__be64));
7309b8c81d1SSteven Whitehouse 				ptr = (__be64 *)(mp->mp_bh[i]->b_data +
7319b8c81d1SSteven Whitehouse 					sizeof(struct gfs2_meta_header));
7329b8c81d1SSteven Whitehouse 				*ptr = zero_bn;
7339b8c81d1SSteven Whitehouse 				state = ALLOC_GROW_DEPTH;
7345f8bd444SBob Peterson 				for(i = branch_start; i < mp->mp_fheight; i++) {
7359b8c81d1SSteven Whitehouse 					if (mp->mp_bh[i] == NULL)
7369b8c81d1SSteven Whitehouse 						break;
7379b8c81d1SSteven Whitehouse 					brelse(mp->mp_bh[i]);
7389b8c81d1SSteven Whitehouse 					mp->mp_bh[i] = NULL;
7399b8c81d1SSteven Whitehouse 				}
7405af4e7a0SBenjamin Marzinski 				i = branch_start;
7419b8c81d1SSteven Whitehouse 			}
7429b8c81d1SSteven Whitehouse 			if (n == 0)
7439b8c81d1SSteven Whitehouse 				break;
744df561f66SGustavo A. R. Silva 			fallthrough;	/* To branching from existing tree */
7459b8c81d1SSteven Whitehouse 		case ALLOC_GROW_DEPTH:
7465f8bd444SBob Peterson 			if (i > 1 && i < mp->mp_fheight)
747350a9b0aSSteven Whitehouse 				gfs2_trans_add_meta(ip->i_gl, mp->mp_bh[i-1]);
7485f8bd444SBob Peterson 			for (; i < mp->mp_fheight && n > 0; i++, n--)
7499b8c81d1SSteven Whitehouse 				gfs2_indirect_init(mp, ip->i_gl, i,
7509b8c81d1SSteven Whitehouse 						   mp->mp_list[i-1], bn++);
7515f8bd444SBob Peterson 			if (i == mp->mp_fheight)
7529b8c81d1SSteven Whitehouse 				state = ALLOC_DATA;
7539b8c81d1SSteven Whitehouse 			if (n == 0)
7549b8c81d1SSteven Whitehouse 				break;
755df561f66SGustavo A. R. Silva 			fallthrough;	/* To tree complete, adding data blocks */
7569b8c81d1SSteven Whitehouse 		case ALLOC_DATA:
7573974320cSBob Peterson 			BUG_ON(n > dblks);
7589b8c81d1SSteven Whitehouse 			BUG_ON(mp->mp_bh[end_of_metadata] == NULL);
759350a9b0aSSteven Whitehouse 			gfs2_trans_add_meta(ip->i_gl, mp->mp_bh[end_of_metadata]);
7603974320cSBob Peterson 			dblks = n;
7619b8c81d1SSteven Whitehouse 			ptr = metapointer(end_of_metadata, mp);
7623974320cSBob Peterson 			iomap->addr = bn << inode->i_blkbits;
763628e366dSAndreas Gruenbacher 			iomap->flags |= IOMAP_F_MERGED | IOMAP_F_NEW;
7649b8c81d1SSteven Whitehouse 			while (n-- > 0)
7659b8c81d1SSteven Whitehouse 				*ptr++ = cpu_to_be64(bn++);
7669b8c81d1SSteven Whitehouse 			break;
7679b8c81d1SSteven Whitehouse 		}
7683974320cSBob Peterson 	} while (iomap->addr == IOMAP_NULL_ADDR);
7699b8c81d1SSteven Whitehouse 
770d505a96aSAndreas Gruenbacher 	iomap->type = IOMAP_MAPPED;
7713974320cSBob Peterson 	iomap->length = (u64)dblks << inode->i_blkbits;
7725f8bd444SBob Peterson 	ip->i_height = mp->mp_fheight;
7739b8c81d1SSteven Whitehouse 	gfs2_add_inode_blocks(&ip->i_inode, alloced);
774628e366dSAndreas Gruenbacher 	gfs2_dinode_out(ip, dibh->b_data);
775628e366dSAndreas Gruenbacher out:
776628e366dSAndreas Gruenbacher 	up_write(&ip->i_rw_mutex);
777628e366dSAndreas Gruenbacher 	return ret;
7789b8c81d1SSteven Whitehouse }
7799b8c81d1SSteven Whitehouse 
7807ee66c03SChristoph Hellwig #define IOMAP_F_GFS2_BOUNDARY IOMAP_F_PRIVATE
7817ee66c03SChristoph Hellwig 
7823974320cSBob Peterson /**
78364bc06bbSAndreas Gruenbacher  * gfs2_alloc_size - Compute the maximum allocation size
78464bc06bbSAndreas Gruenbacher  * @inode: The inode
78564bc06bbSAndreas Gruenbacher  * @mp: The metapath
78664bc06bbSAndreas Gruenbacher  * @size: Requested size in blocks
78764bc06bbSAndreas Gruenbacher  *
78864bc06bbSAndreas Gruenbacher  * Compute the maximum size of the next allocation at @mp.
78964bc06bbSAndreas Gruenbacher  *
79064bc06bbSAndreas Gruenbacher  * Returns: size in blocks
79164bc06bbSAndreas Gruenbacher  */
gfs2_alloc_size(struct inode * inode,struct metapath * mp,u64 size)79264bc06bbSAndreas Gruenbacher static u64 gfs2_alloc_size(struct inode *inode, struct metapath *mp, u64 size)
7933974320cSBob Peterson {
7943974320cSBob Peterson 	struct gfs2_inode *ip = GFS2_I(inode);
79564bc06bbSAndreas Gruenbacher 	struct gfs2_sbd *sdp = GFS2_SB(inode);
79664bc06bbSAndreas Gruenbacher 	const __be64 *first, *ptr, *end;
7973974320cSBob Peterson 
79864bc06bbSAndreas Gruenbacher 	/*
79964bc06bbSAndreas Gruenbacher 	 * For writes to stuffed files, this function is called twice via
80054992257SAndreas Gruenbacher 	 * __gfs2_iomap_get, before and after unstuffing. The size we return the
80164bc06bbSAndreas Gruenbacher 	 * first time needs to be large enough to get the reservation and
80264bc06bbSAndreas Gruenbacher 	 * allocation sizes right.  The size we return the second time must
80354992257SAndreas Gruenbacher 	 * be exact or else __gfs2_iomap_alloc won't do the right thing.
80464bc06bbSAndreas Gruenbacher 	 */
80564bc06bbSAndreas Gruenbacher 
80664bc06bbSAndreas Gruenbacher 	if (gfs2_is_stuffed(ip) || mp->mp_fheight != mp->mp_aheight) {
80764bc06bbSAndreas Gruenbacher 		unsigned int maxsize = mp->mp_fheight > 1 ?
80864bc06bbSAndreas Gruenbacher 			sdp->sd_inptrs : sdp->sd_diptrs;
80964bc06bbSAndreas Gruenbacher 		maxsize -= mp->mp_list[mp->mp_fheight - 1];
81064bc06bbSAndreas Gruenbacher 		if (size > maxsize)
81164bc06bbSAndreas Gruenbacher 			size = maxsize;
81264bc06bbSAndreas Gruenbacher 		return size;
8133974320cSBob Peterson 	}
8143974320cSBob Peterson 
81564bc06bbSAndreas Gruenbacher 	first = metapointer(ip->i_height - 1, mp);
81664bc06bbSAndreas Gruenbacher 	end = metaend(ip->i_height - 1, mp);
81764bc06bbSAndreas Gruenbacher 	if (end - first > size)
81864bc06bbSAndreas Gruenbacher 		end = first + size;
81964bc06bbSAndreas Gruenbacher 	for (ptr = first; ptr < end; ptr++) {
82064bc06bbSAndreas Gruenbacher 		if (*ptr)
82164bc06bbSAndreas Gruenbacher 			break;
82264bc06bbSAndreas Gruenbacher 	}
82364bc06bbSAndreas Gruenbacher 	return ptr - first;
82464bc06bbSAndreas Gruenbacher }
8253974320cSBob Peterson 
8263974320cSBob Peterson /**
82754992257SAndreas Gruenbacher  * __gfs2_iomap_get - Map blocks from an inode to disk blocks
8283974320cSBob Peterson  * @inode: The inode
8293974320cSBob Peterson  * @pos: Starting position in bytes
8303974320cSBob Peterson  * @length: Length to map, in bytes
8313974320cSBob Peterson  * @flags: iomap flags
8323974320cSBob Peterson  * @iomap: The iomap structure
833628e366dSAndreas Gruenbacher  * @mp: The metapath
8343974320cSBob Peterson  *
8353974320cSBob Peterson  * Returns: errno
8363974320cSBob Peterson  */
__gfs2_iomap_get(struct inode * inode,loff_t pos,loff_t length,unsigned flags,struct iomap * iomap,struct metapath * mp)83754992257SAndreas Gruenbacher static int __gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length,
838628e366dSAndreas Gruenbacher 			    unsigned flags, struct iomap *iomap,
839628e366dSAndreas Gruenbacher 			    struct metapath *mp)
8403974320cSBob Peterson {
8413974320cSBob Peterson 	struct gfs2_inode *ip = GFS2_I(inode);
8423974320cSBob Peterson 	struct gfs2_sbd *sdp = GFS2_SB(inode);
843d505a96aSAndreas Gruenbacher 	loff_t size = i_size_read(inode);
8443974320cSBob Peterson 	__be64 *ptr;
8453974320cSBob Peterson 	sector_t lblock;
846628e366dSAndreas Gruenbacher 	sector_t lblock_stop;
847628e366dSAndreas Gruenbacher 	int ret;
8483974320cSBob Peterson 	int eob;
849628e366dSAndreas Gruenbacher 	u64 len;
850d505a96aSAndreas Gruenbacher 	struct buffer_head *dibh = NULL, *bh;
8513974320cSBob Peterson 	u8 height;
8523974320cSBob Peterson 
853628e366dSAndreas Gruenbacher 	if (!length)
854628e366dSAndreas Gruenbacher 		return -EINVAL;
8553974320cSBob Peterson 
856d505a96aSAndreas Gruenbacher 	down_read(&ip->i_rw_mutex);
857d505a96aSAndreas Gruenbacher 
858d505a96aSAndreas Gruenbacher 	ret = gfs2_meta_inode_buffer(ip, &dibh);
859d505a96aSAndreas Gruenbacher 	if (ret)
860d505a96aSAndreas Gruenbacher 		goto unlock;
861c26b5aa8SAndreas Gruenbacher 	mp->mp_bh[0] = dibh;
862d505a96aSAndreas Gruenbacher 
86349edd5bfSAndreas Gruenbacher 	if (gfs2_is_stuffed(ip)) {
864d505a96aSAndreas Gruenbacher 		if (flags & IOMAP_WRITE) {
865d505a96aSAndreas Gruenbacher 			loff_t max_size = gfs2_max_stuffed_size(ip);
866d505a96aSAndreas Gruenbacher 
867d505a96aSAndreas Gruenbacher 			if (pos + length > max_size)
868d505a96aSAndreas Gruenbacher 				goto unstuff;
869d505a96aSAndreas Gruenbacher 			iomap->length = max_size;
870d505a96aSAndreas Gruenbacher 		} else {
871d505a96aSAndreas Gruenbacher 			if (pos >= size) {
87249edd5bfSAndreas Gruenbacher 				if (flags & IOMAP_REPORT) {
873d505a96aSAndreas Gruenbacher 					ret = -ENOENT;
874d505a96aSAndreas Gruenbacher 					goto unlock;
875d505a96aSAndreas Gruenbacher 				} else {
876d505a96aSAndreas Gruenbacher 					iomap->offset = pos;
877d505a96aSAndreas Gruenbacher 					iomap->length = length;
878566a2ab3SAndreas Gruenbacher 					goto hole_found;
8793974320cSBob Peterson 				}
88049edd5bfSAndreas Gruenbacher 			}
881d505a96aSAndreas Gruenbacher 			iomap->length = size;
882d505a96aSAndreas Gruenbacher 		}
883d505a96aSAndreas Gruenbacher 		iomap->addr = (ip->i_no_addr << inode->i_blkbits) +
884d505a96aSAndreas Gruenbacher 			      sizeof(struct gfs2_dinode);
885d505a96aSAndreas Gruenbacher 		iomap->type = IOMAP_INLINE;
88664bc06bbSAndreas Gruenbacher 		iomap->inline_data = dibh->b_data + sizeof(struct gfs2_dinode);
887d505a96aSAndreas Gruenbacher 		goto out;
888d505a96aSAndreas Gruenbacher 	}
889d505a96aSAndreas Gruenbacher 
890d505a96aSAndreas Gruenbacher unstuff:
8913974320cSBob Peterson 	lblock = pos >> inode->i_blkbits;
8923974320cSBob Peterson 	iomap->offset = lblock << inode->i_blkbits;
893628e366dSAndreas Gruenbacher 	lblock_stop = (pos + length - 1) >> inode->i_blkbits;
894628e366dSAndreas Gruenbacher 	len = lblock_stop - lblock + 1;
895d505a96aSAndreas Gruenbacher 	iomap->length = len << inode->i_blkbits;
8963974320cSBob Peterson 
8973974320cSBob Peterson 	height = ip->i_height;
8989a38662bSAndreas Gruenbacher 	while ((lblock + 1) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height])
8993974320cSBob Peterson 		height++;
900628e366dSAndreas Gruenbacher 	find_metapath(sdp, lblock, mp, height);
9013974320cSBob Peterson 	if (height > ip->i_height || gfs2_is_stuffed(ip))
9023974320cSBob Peterson 		goto do_alloc;
9033974320cSBob Peterson 
904628e366dSAndreas Gruenbacher 	ret = lookup_metapath(ip, mp);
905e8b43fe0SAndreas Gruenbacher 	if (ret)
906628e366dSAndreas Gruenbacher 		goto unlock;
9073974320cSBob Peterson 
908628e366dSAndreas Gruenbacher 	if (mp->mp_aheight != ip->i_height)
9093974320cSBob Peterson 		goto do_alloc;
9103974320cSBob Peterson 
911628e366dSAndreas Gruenbacher 	ptr = metapointer(ip->i_height - 1, mp);
9123974320cSBob Peterson 	if (*ptr == 0)
9133974320cSBob Peterson 		goto do_alloc;
9143974320cSBob Peterson 
915628e366dSAndreas Gruenbacher 	bh = mp->mp_bh[ip->i_height - 1];
916bcfe9413SAndreas Gruenbacher 	len = gfs2_extent_length(bh, ptr, len, &eob);
9173974320cSBob Peterson 
918628e366dSAndreas Gruenbacher 	iomap->addr = be64_to_cpu(*ptr) << inode->i_blkbits;
919628e366dSAndreas Gruenbacher 	iomap->length = len << inode->i_blkbits;
920628e366dSAndreas Gruenbacher 	iomap->type = IOMAP_MAPPED;
9210ed91ecaSAndreas Gruenbacher 	iomap->flags |= IOMAP_F_MERGED;
9223974320cSBob Peterson 	if (eob)
9237ee66c03SChristoph Hellwig 		iomap->flags |= IOMAP_F_GFS2_BOUNDARY;
9243974320cSBob Peterson 
9253974320cSBob Peterson out:
926628e366dSAndreas Gruenbacher 	iomap->bdev = inode->i_sb->s_bdev;
927628e366dSAndreas Gruenbacher unlock:
928628e366dSAndreas Gruenbacher 	up_read(&ip->i_rw_mutex);
9293974320cSBob Peterson 	return ret;
9303974320cSBob Peterson 
9313974320cSBob Peterson do_alloc:
932628e366dSAndreas Gruenbacher 	if (flags & IOMAP_REPORT) {
93349edd5bfSAndreas Gruenbacher 		if (pos >= size)
93449edd5bfSAndreas Gruenbacher 			ret = -ENOENT;
935628e366dSAndreas Gruenbacher 		else if (height == ip->i_height)
936628e366dSAndreas Gruenbacher 			ret = gfs2_hole_size(inode, lblock, len, mp, iomap);
93749edd5bfSAndreas Gruenbacher 		else
938f3506eeeSAndreas Gruenbacher 			iomap->length = size - iomap->offset;
93964bc06bbSAndreas Gruenbacher 	} else if (flags & IOMAP_WRITE) {
94064bc06bbSAndreas Gruenbacher 		u64 alloc_size;
94164bc06bbSAndreas Gruenbacher 
942967bcc91SAndreas Gruenbacher 		if (flags & IOMAP_DIRECT)
943967bcc91SAndreas Gruenbacher 			goto out;  /* (see gfs2_file_direct_write) */
944967bcc91SAndreas Gruenbacher 
94564bc06bbSAndreas Gruenbacher 		len = gfs2_alloc_size(inode, mp, len);
94664bc06bbSAndreas Gruenbacher 		alloc_size = len << inode->i_blkbits;
94764bc06bbSAndreas Gruenbacher 		if (alloc_size < iomap->length)
94864bc06bbSAndreas Gruenbacher 			iomap->length = alloc_size;
94964bc06bbSAndreas Gruenbacher 	} else {
950d505a96aSAndreas Gruenbacher 		if (pos < size && height == ip->i_height)
951d505a96aSAndreas Gruenbacher 			ret = gfs2_hole_size(inode, lblock, len, mp, iomap);
95249edd5bfSAndreas Gruenbacher 	}
953566a2ab3SAndreas Gruenbacher hole_found:
954566a2ab3SAndreas Gruenbacher 	iomap->addr = IOMAP_NULL_ADDR;
955566a2ab3SAndreas Gruenbacher 	iomap->type = IOMAP_HOLE;
956628e366dSAndreas Gruenbacher 	goto out;
9573974320cSBob Peterson }
9583974320cSBob Peterson 
9599060bc4dSAndreas Gruenbacher static struct folio *
gfs2_iomap_get_folio(struct iomap_iter * iter,loff_t pos,unsigned len)960c82abc23SAndreas Gruenbacher gfs2_iomap_get_folio(struct iomap_iter *iter, loff_t pos, unsigned len)
961d0a22a4bSAndreas Gruenbacher {
9629060bc4dSAndreas Gruenbacher 	struct inode *inode = iter->inode;
9632741b672SAndreas Gruenbacher 	unsigned int blockmask = i_blocksize(inode) - 1;
964d0a22a4bSAndreas Gruenbacher 	struct gfs2_sbd *sdp = GFS2_SB(inode);
9652741b672SAndreas Gruenbacher 	unsigned int blocks;
9669060bc4dSAndreas Gruenbacher 	struct folio *folio;
9679060bc4dSAndreas Gruenbacher 	int status;
968d0a22a4bSAndreas Gruenbacher 
9692741b672SAndreas Gruenbacher 	blocks = ((pos & blockmask) + len + blockmask) >> inode->i_blkbits;
9709060bc4dSAndreas Gruenbacher 	status = gfs2_trans_begin(sdp, RES_DINODE + blocks, 0);
9719060bc4dSAndreas Gruenbacher 	if (status)
9729060bc4dSAndreas Gruenbacher 		return ERR_PTR(status);
9739060bc4dSAndreas Gruenbacher 
974d6bb59a9SMatthew Wilcox (Oracle) 	folio = iomap_get_folio(iter, pos, len);
9759060bc4dSAndreas Gruenbacher 	if (IS_ERR(folio))
9769060bc4dSAndreas Gruenbacher 		gfs2_trans_end(sdp);
9779060bc4dSAndreas Gruenbacher 	return folio;
978d0a22a4bSAndreas Gruenbacher }
979d0a22a4bSAndreas Gruenbacher 
gfs2_iomap_put_folio(struct inode * inode,loff_t pos,unsigned copied,struct folio * folio)98040405dddSAndreas Gruenbacher static void gfs2_iomap_put_folio(struct inode *inode, loff_t pos,
98180baab88SAndreas Gruenbacher 				 unsigned copied, struct folio *folio)
98264bc06bbSAndreas Gruenbacher {
983706cb549SAndreas Gruenbacher 	struct gfs2_trans *tr = current->journal_info;
98464bc06bbSAndreas Gruenbacher 	struct gfs2_inode *ip = GFS2_I(inode);
985d0a22a4bSAndreas Gruenbacher 	struct gfs2_sbd *sdp = GFS2_SB(inode);
98664bc06bbSAndreas Gruenbacher 
98780baab88SAndreas Gruenbacher 	if (!gfs2_is_stuffed(ip))
988c1b0c3cfSAndreas Gruenbacher 		gfs2_trans_add_databufs(ip, folio, offset_in_folio(folio, pos),
98980baab88SAndreas Gruenbacher 					copied);
99080baab88SAndreas Gruenbacher 
99180baab88SAndreas Gruenbacher 	folio_unlock(folio);
99280baab88SAndreas Gruenbacher 	folio_put(folio);
993706cb549SAndreas Gruenbacher 
994706cb549SAndreas Gruenbacher 	if (tr->tr_num_buf_new)
995706cb549SAndreas Gruenbacher 		__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
996706cb549SAndreas Gruenbacher 
997d0a22a4bSAndreas Gruenbacher 	gfs2_trans_end(sdp);
99864bc06bbSAndreas Gruenbacher }
99964bc06bbSAndreas Gruenbacher 
1000471859f5SAndreas Gruenbacher static const struct iomap_folio_ops gfs2_iomap_folio_ops = {
1001c82abc23SAndreas Gruenbacher 	.get_folio = gfs2_iomap_get_folio,
100240405dddSAndreas Gruenbacher 	.put_folio = gfs2_iomap_put_folio,
1003df0db3ecSAndreas Gruenbacher };
1004df0db3ecSAndreas Gruenbacher 
gfs2_iomap_begin_write(struct inode * inode,loff_t pos,loff_t length,unsigned flags,struct iomap * iomap,struct metapath * mp)100564bc06bbSAndreas Gruenbacher static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
100664bc06bbSAndreas Gruenbacher 				  loff_t length, unsigned flags,
1007c26b5aa8SAndreas Gruenbacher 				  struct iomap *iomap,
1008c26b5aa8SAndreas Gruenbacher 				  struct metapath *mp)
100964bc06bbSAndreas Gruenbacher {
101064bc06bbSAndreas Gruenbacher 	struct gfs2_inode *ip = GFS2_I(inode);
101164bc06bbSAndreas Gruenbacher 	struct gfs2_sbd *sdp = GFS2_SB(inode);
101234aad20bSAndreas Gruenbacher 	bool unstuff;
101364bc06bbSAndreas Gruenbacher 	int ret;
101464bc06bbSAndreas Gruenbacher 
101564bc06bbSAndreas Gruenbacher 	unstuff = gfs2_is_stuffed(ip) &&
101664bc06bbSAndreas Gruenbacher 		  pos + length > gfs2_max_stuffed_size(ip);
101764bc06bbSAndreas Gruenbacher 
101834aad20bSAndreas Gruenbacher 	if (unstuff || iomap->type == IOMAP_HOLE) {
101934aad20bSAndreas Gruenbacher 		unsigned int data_blocks, ind_blocks;
102034aad20bSAndreas Gruenbacher 		struct gfs2_alloc_parms ap = {};
102134aad20bSAndreas Gruenbacher 		unsigned int rblocks;
102234aad20bSAndreas Gruenbacher 		struct gfs2_trans *tr;
102364bc06bbSAndreas Gruenbacher 
102464bc06bbSAndreas Gruenbacher 		gfs2_write_calc_reserv(ip, iomap->length, &data_blocks,
102564bc06bbSAndreas Gruenbacher 				       &ind_blocks);
102634aad20bSAndreas Gruenbacher 		ap.target = data_blocks + ind_blocks;
102764bc06bbSAndreas Gruenbacher 		ret = gfs2_quota_lock_check(ip, &ap);
102864bc06bbSAndreas Gruenbacher 		if (ret)
102934aad20bSAndreas Gruenbacher 			return ret;
103064bc06bbSAndreas Gruenbacher 
103164bc06bbSAndreas Gruenbacher 		ret = gfs2_inplace_reserve(ip, &ap);
103264bc06bbSAndreas Gruenbacher 		if (ret)
103364bc06bbSAndreas Gruenbacher 			goto out_qunlock;
103464bc06bbSAndreas Gruenbacher 
103564bc06bbSAndreas Gruenbacher 		rblocks = RES_DINODE + ind_blocks;
103664bc06bbSAndreas Gruenbacher 		if (gfs2_is_jdata(ip))
103764bc06bbSAndreas Gruenbacher 			rblocks += data_blocks;
103864bc06bbSAndreas Gruenbacher 		if (ind_blocks || data_blocks)
103964bc06bbSAndreas Gruenbacher 			rblocks += RES_STATFS + RES_QUOTA;
104064bc06bbSAndreas Gruenbacher 		if (inode == sdp->sd_rindex)
104164bc06bbSAndreas Gruenbacher 			rblocks += 2 * RES_STATFS;
104264bc06bbSAndreas Gruenbacher 		rblocks += gfs2_rg_blocks(ip, data_blocks + ind_blocks);
104364bc06bbSAndreas Gruenbacher 
1044d0a22a4bSAndreas Gruenbacher 		ret = gfs2_trans_begin(sdp, rblocks,
1045d0a22a4bSAndreas Gruenbacher 				       iomap->length >> inode->i_blkbits);
104664bc06bbSAndreas Gruenbacher 		if (ret)
104764bc06bbSAndreas Gruenbacher 			goto out_trans_fail;
104864bc06bbSAndreas Gruenbacher 
104964bc06bbSAndreas Gruenbacher 		if (unstuff) {
10507a607a41SAndreas Gruenbacher 			ret = gfs2_unstuff_dinode(ip);
105164bc06bbSAndreas Gruenbacher 			if (ret)
105264bc06bbSAndreas Gruenbacher 				goto out_trans_end;
1053c26b5aa8SAndreas Gruenbacher 			release_metapath(mp);
105454992257SAndreas Gruenbacher 			ret = __gfs2_iomap_get(inode, iomap->offset,
1055d0a22a4bSAndreas Gruenbacher 					       iomap->length, flags, iomap, mp);
105664bc06bbSAndreas Gruenbacher 			if (ret)
105764bc06bbSAndreas Gruenbacher 				goto out_trans_end;
105864bc06bbSAndreas Gruenbacher 		}
105964bc06bbSAndreas Gruenbacher 
106064bc06bbSAndreas Gruenbacher 		if (iomap->type == IOMAP_HOLE) {
106154992257SAndreas Gruenbacher 			ret = __gfs2_iomap_alloc(inode, iomap, mp);
106264bc06bbSAndreas Gruenbacher 			if (ret) {
106364bc06bbSAndreas Gruenbacher 				gfs2_trans_end(sdp);
106464bc06bbSAndreas Gruenbacher 				gfs2_inplace_release(ip);
106564bc06bbSAndreas Gruenbacher 				punch_hole(ip, iomap->offset, iomap->length);
106664bc06bbSAndreas Gruenbacher 				goto out_qunlock;
106764bc06bbSAndreas Gruenbacher 			}
106864bc06bbSAndreas Gruenbacher 		}
1069d0a22a4bSAndreas Gruenbacher 
1070d0a22a4bSAndreas Gruenbacher 		tr = current->journal_info;
1071d0a22a4bSAndreas Gruenbacher 		if (tr->tr_num_buf_new)
1072d0a22a4bSAndreas Gruenbacher 			__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
1073d0a22a4bSAndreas Gruenbacher 
1074d0a22a4bSAndreas Gruenbacher 		gfs2_trans_end(sdp);
1075d0a22a4bSAndreas Gruenbacher 	}
1076d0a22a4bSAndreas Gruenbacher 
1077d0a22a4bSAndreas Gruenbacher 	if (gfs2_is_stuffed(ip) || gfs2_is_jdata(ip))
1078471859f5SAndreas Gruenbacher 		iomap->folio_ops = &gfs2_iomap_folio_ops;
107964bc06bbSAndreas Gruenbacher 	return 0;
108064bc06bbSAndreas Gruenbacher 
108164bc06bbSAndreas Gruenbacher out_trans_end:
108264bc06bbSAndreas Gruenbacher 	gfs2_trans_end(sdp);
108364bc06bbSAndreas Gruenbacher out_trans_fail:
108464bc06bbSAndreas Gruenbacher 	gfs2_inplace_release(ip);
108564bc06bbSAndreas Gruenbacher out_qunlock:
108664bc06bbSAndreas Gruenbacher 	gfs2_quota_unlock(ip);
108764bc06bbSAndreas Gruenbacher 	return ret;
108864bc06bbSAndreas Gruenbacher }
108964bc06bbSAndreas Gruenbacher 
gfs2_iomap_begin(struct inode * inode,loff_t pos,loff_t length,unsigned flags,struct iomap * iomap,struct iomap * srcmap)1090628e366dSAndreas Gruenbacher static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
1091c039b997SGoldwyn Rodrigues 			    unsigned flags, struct iomap *iomap,
1092c039b997SGoldwyn Rodrigues 			    struct iomap *srcmap)
1093628e366dSAndreas Gruenbacher {
1094628e366dSAndreas Gruenbacher 	struct gfs2_inode *ip = GFS2_I(inode);
1095628e366dSAndreas Gruenbacher 	struct metapath mp = { .mp_aheight = 1, };
1096628e366dSAndreas Gruenbacher 	int ret;
1097628e366dSAndreas Gruenbacher 
10982164f9b9SChristoph Hellwig 	if (gfs2_is_jdata(ip))
10990ed91ecaSAndreas Gruenbacher 		iomap->flags |= IOMAP_F_BUFFER_HEAD;
11000ed91ecaSAndreas Gruenbacher 
1101628e366dSAndreas Gruenbacher 	trace_gfs2_iomap_start(ip, pos, length, flags);
110254992257SAndreas Gruenbacher 	ret = __gfs2_iomap_get(inode, pos, length, flags, iomap, &mp);
110334aad20bSAndreas Gruenbacher 	if (ret)
110434aad20bSAndreas Gruenbacher 		goto out_unlock;
110534aad20bSAndreas Gruenbacher 
110672d36d05SAndreas Gruenbacher 	switch(flags & (IOMAP_WRITE | IOMAP_ZERO)) {
110734aad20bSAndreas Gruenbacher 	case IOMAP_WRITE:
110834aad20bSAndreas Gruenbacher 		if (flags & IOMAP_DIRECT) {
110934aad20bSAndreas Gruenbacher 			/*
111034aad20bSAndreas Gruenbacher 			 * Silently fall back to buffered I/O for stuffed files
111134aad20bSAndreas Gruenbacher 			 * or if we've got a hole (see gfs2_file_direct_write).
111234aad20bSAndreas Gruenbacher 			 */
111334aad20bSAndreas Gruenbacher 			if (iomap->type != IOMAP_MAPPED)
111434aad20bSAndreas Gruenbacher 				ret = -ENOTBLK;
111534aad20bSAndreas Gruenbacher 			goto out_unlock;
111634aad20bSAndreas Gruenbacher 		}
111734aad20bSAndreas Gruenbacher 		break;
111872d36d05SAndreas Gruenbacher 	case IOMAP_ZERO:
111972d36d05SAndreas Gruenbacher 		if (iomap->type == IOMAP_HOLE)
112072d36d05SAndreas Gruenbacher 			goto out_unlock;
112172d36d05SAndreas Gruenbacher 		break;
112234aad20bSAndreas Gruenbacher 	default:
112334aad20bSAndreas Gruenbacher 		goto out_unlock;
112434aad20bSAndreas Gruenbacher 	}
112534aad20bSAndreas Gruenbacher 
112634aad20bSAndreas Gruenbacher 	ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp);
112734aad20bSAndreas Gruenbacher 
112834aad20bSAndreas Gruenbacher out_unlock:
1129c26b5aa8SAndreas Gruenbacher 	release_metapath(&mp);
1130628e366dSAndreas Gruenbacher 	trace_gfs2_iomap_end(ip, iomap, ret);
1131628e366dSAndreas Gruenbacher 	return ret;
1132628e366dSAndreas Gruenbacher }
1133628e366dSAndreas Gruenbacher 
gfs2_iomap_end(struct inode * inode,loff_t pos,loff_t length,ssize_t written,unsigned flags,struct iomap * iomap)113464bc06bbSAndreas Gruenbacher static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
113564bc06bbSAndreas Gruenbacher 			  ssize_t written, unsigned flags, struct iomap *iomap)
113664bc06bbSAndreas Gruenbacher {
113764bc06bbSAndreas Gruenbacher 	struct gfs2_inode *ip = GFS2_I(inode);
113864bc06bbSAndreas Gruenbacher 	struct gfs2_sbd *sdp = GFS2_SB(inode);
113964bc06bbSAndreas Gruenbacher 
114072d36d05SAndreas Gruenbacher 	switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) {
114134aad20bSAndreas Gruenbacher 	case IOMAP_WRITE:
114234aad20bSAndreas Gruenbacher 		if (flags & IOMAP_DIRECT)
114334aad20bSAndreas Gruenbacher 			return 0;
114434aad20bSAndreas Gruenbacher 		break;
114572d36d05SAndreas Gruenbacher 	case IOMAP_ZERO:
114672d36d05SAndreas Gruenbacher 		 if (iomap->type == IOMAP_HOLE)
114772d36d05SAndreas Gruenbacher 			 return 0;
114872d36d05SAndreas Gruenbacher 		 break;
114934aad20bSAndreas Gruenbacher 	default:
115034aad20bSAndreas Gruenbacher 		 return 0;
115134aad20bSAndreas Gruenbacher 	}
115264bc06bbSAndreas Gruenbacher 
1153d0a22a4bSAndreas Gruenbacher 	if (!gfs2_is_stuffed(ip))
115464bc06bbSAndreas Gruenbacher 		gfs2_ordered_add_inode(ip);
115564bc06bbSAndreas Gruenbacher 
1156d0a22a4bSAndreas Gruenbacher 	if (inode == sdp->sd_rindex)
115764bc06bbSAndreas Gruenbacher 		adjust_fs_space(inode);
115864bc06bbSAndreas Gruenbacher 
115964bc06bbSAndreas Gruenbacher 	gfs2_inplace_release(ip);
116064bc06bbSAndreas Gruenbacher 
11617009fa9cSAndreas Gruenbacher 	if (ip->i_qadata && ip->i_qadata->qa_qd_num)
11627009fa9cSAndreas Gruenbacher 		gfs2_quota_unlock(ip);
11637009fa9cSAndreas Gruenbacher 
116464bc06bbSAndreas Gruenbacher 	if (length != written && (iomap->flags & IOMAP_F_NEW)) {
116564bc06bbSAndreas Gruenbacher 		/* Deallocate blocks that were just allocated. */
1166d031a886SAndreas Gruenbacher 		loff_t hstart = round_up(pos + written, i_blocksize(inode));
1167d031a886SAndreas Gruenbacher 		loff_t hend = iomap->offset + iomap->length;
116864bc06bbSAndreas Gruenbacher 
1169d031a886SAndreas Gruenbacher 		if (hstart < hend) {
1170d031a886SAndreas Gruenbacher 			truncate_pagecache_range(inode, hstart, hend - 1);
1171d031a886SAndreas Gruenbacher 			punch_hole(ip, hstart, hend - hstart);
117264bc06bbSAndreas Gruenbacher 		}
117364bc06bbSAndreas Gruenbacher 	}
117464bc06bbSAndreas Gruenbacher 
1175706cb549SAndreas Gruenbacher 	if (unlikely(!written))
1176b924bdabSAndreas Gruenbacher 		return 0;
1177706cb549SAndreas Gruenbacher 
11788d3e72a1SAndreas Gruenbacher 	if (iomap->flags & IOMAP_F_SIZE_CHANGED)
11798d3e72a1SAndreas Gruenbacher 		mark_inode_dirty(inode);
1180706cb549SAndreas Gruenbacher 	set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
118164bc06bbSAndreas Gruenbacher 	return 0;
118264bc06bbSAndreas Gruenbacher }
118364bc06bbSAndreas Gruenbacher 
1184628e366dSAndreas Gruenbacher const struct iomap_ops gfs2_iomap_ops = {
1185628e366dSAndreas Gruenbacher 	.iomap_begin = gfs2_iomap_begin,
118664bc06bbSAndreas Gruenbacher 	.iomap_end = gfs2_iomap_end,
1187628e366dSAndreas Gruenbacher };
1188628e366dSAndreas Gruenbacher 
11893974320cSBob Peterson /**
1190d39d18e0SAndreas Gruenbacher  * gfs2_block_map - Map one or more blocks of an inode to a disk block
11914cf1ed81SSteven Whitehouse  * @inode: The inode
11924cf1ed81SSteven Whitehouse  * @lblock: The logical block number
11934cf1ed81SSteven Whitehouse  * @bh_map: The bh to be mapped
11949b8c81d1SSteven Whitehouse  * @create: True if its ok to alloc blocks to satify the request
11954cf1ed81SSteven Whitehouse  *
1196d39d18e0SAndreas Gruenbacher  * The size of the requested mapping is defined in bh_map->b_size.
1197d39d18e0SAndreas Gruenbacher  *
1198d39d18e0SAndreas Gruenbacher  * Clears buffer_mapped(bh_map) and leaves bh_map->b_size unchanged
1199d39d18e0SAndreas Gruenbacher  * when @lblock is not mapped.  Sets buffer_mapped(bh_map) and
1200d39d18e0SAndreas Gruenbacher  * bh_map->b_size to indicate the size of the mapping when @lblock and
1201d39d18e0SAndreas Gruenbacher  * successive blocks are mapped, up to the requested size.
1202d39d18e0SAndreas Gruenbacher  *
1203d39d18e0SAndreas Gruenbacher  * Sets buffer_boundary() if a read of metadata will be required
1204d39d18e0SAndreas Gruenbacher  * before the next block can be mapped. Sets buffer_new() if new
1205d39d18e0SAndreas Gruenbacher  * blocks were allocated.
12064cf1ed81SSteven Whitehouse  *
12074cf1ed81SSteven Whitehouse  * Returns: errno
12084cf1ed81SSteven Whitehouse  */
12094cf1ed81SSteven Whitehouse 
gfs2_block_map(struct inode * inode,sector_t lblock,struct buffer_head * bh_map,int create)1210e9e1ef2bSBob Peterson int gfs2_block_map(struct inode *inode, sector_t lblock,
1211e9e1ef2bSBob Peterson 		   struct buffer_head *bh_map, int create)
1212fd88de56SSteven Whitehouse {
12134cf1ed81SSteven Whitehouse 	struct gfs2_inode *ip = GFS2_I(inode);
1214628e366dSAndreas Gruenbacher 	loff_t pos = (loff_t)lblock << inode->i_blkbits;
1215628e366dSAndreas Gruenbacher 	loff_t length = bh_map->b_size;
1216628e366dSAndreas Gruenbacher 	struct iomap iomap = { };
1217628e366dSAndreas Gruenbacher 	int ret;
12189b8c81d1SSteven Whitehouse 
12194cf1ed81SSteven Whitehouse 	clear_buffer_mapped(bh_map);
12204cf1ed81SSteven Whitehouse 	clear_buffer_new(bh_map);
12214cf1ed81SSteven Whitehouse 	clear_buffer_boundary(bh_map);
122263997775SSteven Whitehouse 	trace_gfs2_bmap(ip, bh_map, lblock, create, 1);
122320cdc193SAndreas Gruenbacher 
122454992257SAndreas Gruenbacher 	if (!create)
122554992257SAndreas Gruenbacher 		ret = gfs2_iomap_get(inode, pos, length, &iomap);
122654992257SAndreas Gruenbacher 	else
122754992257SAndreas Gruenbacher 		ret = gfs2_iomap_alloc(inode, pos, length, &iomap);
1228628e366dSAndreas Gruenbacher 	if (ret)
1229628e366dSAndreas Gruenbacher 		goto out;
1230fd88de56SSteven Whitehouse 
12313974320cSBob Peterson 	if (iomap.length > bh_map->b_size) {
12323974320cSBob Peterson 		iomap.length = bh_map->b_size;
12337ee66c03SChristoph Hellwig 		iomap.flags &= ~IOMAP_F_GFS2_BOUNDARY;
12343974320cSBob Peterson 	}
12353974320cSBob Peterson 	if (iomap.addr != IOMAP_NULL_ADDR)
12363974320cSBob Peterson 		map_bh(bh_map, inode->i_sb, iomap.addr >> inode->i_blkbits);
12373974320cSBob Peterson 	bh_map->b_size = iomap.length;
12387ee66c03SChristoph Hellwig 	if (iomap.flags & IOMAP_F_GFS2_BOUNDARY)
12393974320cSBob Peterson 		set_buffer_boundary(bh_map);
12403974320cSBob Peterson 	if (iomap.flags & IOMAP_F_NEW)
12413974320cSBob Peterson 		set_buffer_new(bh_map);
12423974320cSBob Peterson 
12433974320cSBob Peterson out:
12443974320cSBob Peterson 	trace_gfs2_bmap(ip, bh_map, lblock, create, ret);
12453974320cSBob Peterson 	return ret;
12463974320cSBob Peterson }
12473974320cSBob Peterson 
gfs2_get_extent(struct inode * inode,u64 lblock,u64 * dblock,unsigned int * extlen)12489153dac1SAndreas Gruenbacher int gfs2_get_extent(struct inode *inode, u64 lblock, u64 *dblock,
12499153dac1SAndreas Gruenbacher 		    unsigned int *extlen)
1250fd88de56SSteven Whitehouse {
12519153dac1SAndreas Gruenbacher 	unsigned int blkbits = inode->i_blkbits;
12529153dac1SAndreas Gruenbacher 	struct iomap iomap = { };
12539153dac1SAndreas Gruenbacher 	unsigned int len;
12547a6bbacbSSteven Whitehouse 	int ret;
1255fd88de56SSteven Whitehouse 
12569153dac1SAndreas Gruenbacher 	ret = gfs2_iomap_get(inode, lblock << blkbits, *extlen << blkbits,
12579153dac1SAndreas Gruenbacher 			     &iomap);
12589153dac1SAndreas Gruenbacher 	if (ret)
12597a6bbacbSSteven Whitehouse 		return ret;
12609153dac1SAndreas Gruenbacher 	if (iomap.type != IOMAP_MAPPED)
12619153dac1SAndreas Gruenbacher 		return -EIO;
12629153dac1SAndreas Gruenbacher 	*dblock = iomap.addr >> blkbits;
12639153dac1SAndreas Gruenbacher 	len = iomap.length >> blkbits;
12649153dac1SAndreas Gruenbacher 	if (len < *extlen)
12659153dac1SAndreas Gruenbacher 		*extlen = len;
12669153dac1SAndreas Gruenbacher 	return 0;
12679153dac1SAndreas Gruenbacher }
12689153dac1SAndreas Gruenbacher 
gfs2_alloc_extent(struct inode * inode,u64 lblock,u64 * dblock,unsigned int * extlen,bool * new)12699153dac1SAndreas Gruenbacher int gfs2_alloc_extent(struct inode *inode, u64 lblock, u64 *dblock,
12709153dac1SAndreas Gruenbacher 		      unsigned int *extlen, bool *new)
12719153dac1SAndreas Gruenbacher {
12729153dac1SAndreas Gruenbacher 	unsigned int blkbits = inode->i_blkbits;
12739153dac1SAndreas Gruenbacher 	struct iomap iomap = { };
12749153dac1SAndreas Gruenbacher 	unsigned int len;
12759153dac1SAndreas Gruenbacher 	int ret;
12769153dac1SAndreas Gruenbacher 
12779153dac1SAndreas Gruenbacher 	ret = gfs2_iomap_alloc(inode, lblock << blkbits, *extlen << blkbits,
12789153dac1SAndreas Gruenbacher 			       &iomap);
12799153dac1SAndreas Gruenbacher 	if (ret)
12809153dac1SAndreas Gruenbacher 		return ret;
12819153dac1SAndreas Gruenbacher 	if (iomap.type != IOMAP_MAPPED)
12829153dac1SAndreas Gruenbacher 		return -EIO;
12839153dac1SAndreas Gruenbacher 	*dblock = iomap.addr >> blkbits;
12849153dac1SAndreas Gruenbacher 	len = iomap.length >> blkbits;
12859153dac1SAndreas Gruenbacher 	if (len < *extlen)
12869153dac1SAndreas Gruenbacher 		*extlen = len;
12879153dac1SAndreas Gruenbacher 	*new = iomap.flags & IOMAP_F_NEW;
12889153dac1SAndreas Gruenbacher 	return 0;
1289b3b94faaSDavid Teigland }
1290b3b94faaSDavid Teigland 
129170499cdfSBob Peterson /*
129270499cdfSBob Peterson  * NOTE: Never call gfs2_block_zero_range with an open transaction because it
129370499cdfSBob Peterson  * uses iomap write to perform its actions, which begin their own transactions
1294c82abc23SAndreas Gruenbacher  * (iomap_begin, get_folio, etc.)
129570499cdfSBob Peterson  */
gfs2_block_zero_range(struct inode * inode,loff_t from,unsigned int length)1296bdba0d5eSAndreas Gruenbacher static int gfs2_block_zero_range(struct inode *inode, loff_t from,
1297bdba0d5eSAndreas Gruenbacher 				 unsigned int length)
1298ba7f7290SSteven Whitehouse {
129970499cdfSBob Peterson 	BUG_ON(current->journal_info);
13002257e468SChristoph Hellwig 	return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops);
1301ba7f7290SSteven Whitehouse }
1302ba7f7290SSteven Whitehouse 
1303c62baf65SFabian Frederick #define GFS2_JTRUNC_REVOKES 8192
1304c62baf65SFabian Frederick 
1305fa731fc4SSteven Whitehouse /**
1306fa731fc4SSteven Whitehouse  * gfs2_journaled_truncate - Wrapper for truncate_pagecache for jdata files
1307fa731fc4SSteven Whitehouse  * @inode: The inode being truncated
1308fa731fc4SSteven Whitehouse  * @oldsize: The original (larger) size
1309fa731fc4SSteven Whitehouse  * @newsize: The new smaller size
1310fa731fc4SSteven Whitehouse  *
1311fa731fc4SSteven Whitehouse  * With jdata files, we have to journal a revoke for each block which is
1312fa731fc4SSteven Whitehouse  * truncated. As a result, we need to split this into separate transactions
1313fa731fc4SSteven Whitehouse  * if the number of pages being truncated gets too large.
1314fa731fc4SSteven Whitehouse  */
1315fa731fc4SSteven Whitehouse 
gfs2_journaled_truncate(struct inode * inode,u64 oldsize,u64 newsize)1316fa731fc4SSteven Whitehouse static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize)
1317fa731fc4SSteven Whitehouse {
1318fa731fc4SSteven Whitehouse 	struct gfs2_sbd *sdp = GFS2_SB(inode);
1319fa731fc4SSteven Whitehouse 	u64 max_chunk = GFS2_JTRUNC_REVOKES * sdp->sd_vfs->s_blocksize;
1320fa731fc4SSteven Whitehouse 	u64 chunk;
1321fa731fc4SSteven Whitehouse 	int error;
1322fa731fc4SSteven Whitehouse 
1323fa731fc4SSteven Whitehouse 	while (oldsize != newsize) {
1324e7fdf004SAndreas Gruenbacher 		struct gfs2_trans *tr;
1325e7fdf004SAndreas Gruenbacher 		unsigned int offs;
1326e7fdf004SAndreas Gruenbacher 
1327fa731fc4SSteven Whitehouse 		chunk = oldsize - newsize;
1328fa731fc4SSteven Whitehouse 		if (chunk > max_chunk)
1329fa731fc4SSteven Whitehouse 			chunk = max_chunk;
1330e7fdf004SAndreas Gruenbacher 
1331e7fdf004SAndreas Gruenbacher 		offs = oldsize & ~PAGE_MASK;
1332e7fdf004SAndreas Gruenbacher 		if (offs && chunk > PAGE_SIZE)
1333e7fdf004SAndreas Gruenbacher 			chunk = offs + ((chunk - offs) & PAGE_MASK);
1334e7fdf004SAndreas Gruenbacher 
13357caef267SKirill A. Shutemov 		truncate_pagecache(inode, oldsize - chunk);
1336fa731fc4SSteven Whitehouse 		oldsize -= chunk;
1337e7fdf004SAndreas Gruenbacher 
1338e7fdf004SAndreas Gruenbacher 		tr = current->journal_info;
1339e7fdf004SAndreas Gruenbacher 		if (!test_bit(TR_TOUCHED, &tr->tr_flags))
1340e7fdf004SAndreas Gruenbacher 			continue;
1341e7fdf004SAndreas Gruenbacher 
1342fa731fc4SSteven Whitehouse 		gfs2_trans_end(sdp);
1343fa731fc4SSteven Whitehouse 		error = gfs2_trans_begin(sdp, RES_DINODE, GFS2_JTRUNC_REVOKES);
1344fa731fc4SSteven Whitehouse 		if (error)
1345fa731fc4SSteven Whitehouse 			return error;
1346fa731fc4SSteven Whitehouse 	}
1347fa731fc4SSteven Whitehouse 
1348fa731fc4SSteven Whitehouse 	return 0;
1349fa731fc4SSteven Whitehouse }
1350fa731fc4SSteven Whitehouse 
trunc_start(struct inode * inode,u64 newsize)13518b5860a3SAndreas Gruenbacher static int trunc_start(struct inode *inode, u64 newsize)
1352b3b94faaSDavid Teigland {
1353ff8f33c8SSteven Whitehouse 	struct gfs2_inode *ip = GFS2_I(inode);
1354ff8f33c8SSteven Whitehouse 	struct gfs2_sbd *sdp = GFS2_SB(inode);
135580990f40SAndreas Gruenbacher 	struct buffer_head *dibh = NULL;
1356b3b94faaSDavid Teigland 	int journaled = gfs2_is_jdata(ip);
13578b5860a3SAndreas Gruenbacher 	u64 oldsize = inode->i_size;
1358b3b94faaSDavid Teigland 	int error;
1359b3b94faaSDavid Teigland 
136070499cdfSBob Peterson 	if (!gfs2_is_stuffed(ip)) {
136170499cdfSBob Peterson 		unsigned int blocksize = i_blocksize(inode);
136270499cdfSBob Peterson 		unsigned int offs = newsize & (blocksize - 1);
136370499cdfSBob Peterson 		if (offs) {
136470499cdfSBob Peterson 			error = gfs2_block_zero_range(inode, newsize,
136570499cdfSBob Peterson 						      blocksize - offs);
136670499cdfSBob Peterson 			if (error)
136770499cdfSBob Peterson 				return error;
136870499cdfSBob Peterson 		}
136970499cdfSBob Peterson 	}
1370fa731fc4SSteven Whitehouse 	if (journaled)
1371fa731fc4SSteven Whitehouse 		error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES);
1372fa731fc4SSteven Whitehouse 	else
1373fa731fc4SSteven Whitehouse 		error = gfs2_trans_begin(sdp, RES_DINODE, 0);
1374b3b94faaSDavid Teigland 	if (error)
1375b3b94faaSDavid Teigland 		return error;
1376b3b94faaSDavid Teigland 
1377b3b94faaSDavid Teigland 	error = gfs2_meta_inode_buffer(ip, &dibh);
1378b3b94faaSDavid Teigland 	if (error)
1379b3b94faaSDavid Teigland 		goto out;
1380b3b94faaSDavid Teigland 
1381350a9b0aSSteven Whitehouse 	gfs2_trans_add_meta(ip->i_gl, dibh);
1382ff8f33c8SSteven Whitehouse 
138370499cdfSBob Peterson 	if (gfs2_is_stuffed(ip))
1384ff8f33c8SSteven Whitehouse 		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize);
138570499cdfSBob Peterson 	else
1386383f01fbSSteven Whitehouse 		ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
1387ff8f33c8SSteven Whitehouse 
1388ff8f33c8SSteven Whitehouse 	i_size_write(inode, newsize);
13898a8b8d91SJeff Layton 	ip->i_inode.i_mtime = inode_set_ctime_current(&ip->i_inode);
1390539e5d6bSSteven Whitehouse 	gfs2_dinode_out(ip, dibh->b_data);
1391b3b94faaSDavid Teigland 
1392fa731fc4SSteven Whitehouse 	if (journaled)
1393fa731fc4SSteven Whitehouse 		error = gfs2_journaled_truncate(inode, oldsize, newsize);
1394fa731fc4SSteven Whitehouse 	else
13957caef267SKirill A. Shutemov 		truncate_pagecache(inode, newsize);
1396fa731fc4SSteven Whitehouse 
1397b3b94faaSDavid Teigland out:
139880990f40SAndreas Gruenbacher 	brelse(dibh);
139980990f40SAndreas Gruenbacher 	if (current->journal_info)
1400b3b94faaSDavid Teigland 		gfs2_trans_end(sdp);
1401b3b94faaSDavid Teigland 	return error;
1402b3b94faaSDavid Teigland }
1403b3b94faaSDavid Teigland 
gfs2_iomap_get(struct inode * inode,loff_t pos,loff_t length,struct iomap * iomap)140454992257SAndreas Gruenbacher int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length,
1405628e366dSAndreas Gruenbacher 		   struct iomap *iomap)
1406628e366dSAndreas Gruenbacher {
1407628e366dSAndreas Gruenbacher 	struct metapath mp = { .mp_aheight = 1, };
1408628e366dSAndreas Gruenbacher 	int ret;
1409628e366dSAndreas Gruenbacher 
141054992257SAndreas Gruenbacher 	ret = __gfs2_iomap_get(inode, pos, length, 0, iomap, &mp);
141154992257SAndreas Gruenbacher 	release_metapath(&mp);
141254992257SAndreas Gruenbacher 	return ret;
141354992257SAndreas Gruenbacher }
141454992257SAndreas Gruenbacher 
gfs2_iomap_alloc(struct inode * inode,loff_t pos,loff_t length,struct iomap * iomap)141554992257SAndreas Gruenbacher int gfs2_iomap_alloc(struct inode *inode, loff_t pos, loff_t length,
141654992257SAndreas Gruenbacher 		     struct iomap *iomap)
141754992257SAndreas Gruenbacher {
141854992257SAndreas Gruenbacher 	struct metapath mp = { .mp_aheight = 1, };
141954992257SAndreas Gruenbacher 	int ret;
142054992257SAndreas Gruenbacher 
142154992257SAndreas Gruenbacher 	ret = __gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, iomap, &mp);
1422628e366dSAndreas Gruenbacher 	if (!ret && iomap->type == IOMAP_HOLE)
142354992257SAndreas Gruenbacher 		ret = __gfs2_iomap_alloc(inode, iomap, &mp);
1424628e366dSAndreas Gruenbacher 	release_metapath(&mp);
1425628e366dSAndreas Gruenbacher 	return ret;
1426628e366dSAndreas Gruenbacher }
1427628e366dSAndreas Gruenbacher 
1428d552a2b9SBob Peterson /**
1429d552a2b9SBob Peterson  * sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein
1430d552a2b9SBob Peterson  * @ip: inode
1431c551f66cSLee Jones  * @rd_gh: holder of resource group glock
14325cf26b1eSAndreas Gruenbacher  * @bh: buffer head to sweep
14335cf26b1eSAndreas Gruenbacher  * @start: starting point in bh
14345cf26b1eSAndreas Gruenbacher  * @end: end point in bh
14355cf26b1eSAndreas Gruenbacher  * @meta: true if bh points to metadata (rather than data)
1436d552a2b9SBob Peterson  * @btotal: place to keep count of total blocks freed
1437d552a2b9SBob Peterson  *
1438d552a2b9SBob Peterson  * We sweep a metadata buffer (provided by the metapath) for blocks we need to
1439d552a2b9SBob Peterson  * free, and free them all. However, we do it one rgrp at a time. If this
1440d552a2b9SBob Peterson  * block has references to multiple rgrps, we break it into individual
1441d552a2b9SBob Peterson  * transactions. This allows other processes to use the rgrps while we're
1442d552a2b9SBob Peterson  * focused on a single one, for better concurrency / performance.
1443d552a2b9SBob Peterson  * At every transaction boundary, we rewrite the inode into the journal.
1444d552a2b9SBob Peterson  * That way the bitmaps are kept consistent with the inode and we can recover
1445d552a2b9SBob Peterson  * if we're interrupted by power-outages.
1446d552a2b9SBob Peterson  *
1447d552a2b9SBob Peterson  * Returns: 0, or return code if an error occurred.
1448d552a2b9SBob Peterson  *          *btotal has the total number of blocks freed
1449d552a2b9SBob Peterson  */
sweep_bh_for_rgrps(struct gfs2_inode * ip,struct gfs2_holder * rd_gh,struct buffer_head * bh,__be64 * start,__be64 * end,bool meta,u32 * btotal)1450d552a2b9SBob Peterson static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
14515cf26b1eSAndreas Gruenbacher 			      struct buffer_head *bh, __be64 *start, __be64 *end,
14525cf26b1eSAndreas Gruenbacher 			      bool meta, u32 *btotal)
1453b3b94faaSDavid Teigland {
14549b8c81d1SSteven Whitehouse 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
1455d552a2b9SBob Peterson 	struct gfs2_rgrpd *rgd;
1456d552a2b9SBob Peterson 	struct gfs2_trans *tr;
14575cf26b1eSAndreas Gruenbacher 	__be64 *p;
1458d552a2b9SBob Peterson 	int blks_outside_rgrp;
1459d552a2b9SBob Peterson 	u64 bn, bstart, isize_blks;
1460d552a2b9SBob Peterson 	s64 blen; /* needs to be s64 or gfs2_add_inode_blocks breaks */
1461d552a2b9SBob Peterson 	int ret = 0;
1462d552a2b9SBob Peterson 	bool buf_in_tr = false; /* buffer was added to transaction */
1463b3b94faaSDavid Teigland 
1464d552a2b9SBob Peterson more_rgrps:
14655cf26b1eSAndreas Gruenbacher 	rgd = NULL;
1466d552a2b9SBob Peterson 	if (gfs2_holder_initialized(rd_gh)) {
14676f6597baSAndreas Gruenbacher 		rgd = gfs2_glock2rgrp(rd_gh->gh_gl);
1468d552a2b9SBob Peterson 		gfs2_assert_withdraw(sdp,
1469d552a2b9SBob Peterson 			     gfs2_glock_is_locked_by_me(rd_gh->gh_gl));
14705cf26b1eSAndreas Gruenbacher 	}
14715cf26b1eSAndreas Gruenbacher 	blks_outside_rgrp = 0;
14725cf26b1eSAndreas Gruenbacher 	bstart = 0;
14735cf26b1eSAndreas Gruenbacher 	blen = 0;
14745cf26b1eSAndreas Gruenbacher 
14755cf26b1eSAndreas Gruenbacher 	for (p = start; p < end; p++) {
14765cf26b1eSAndreas Gruenbacher 		if (!*p)
14775cf26b1eSAndreas Gruenbacher 			continue;
14785cf26b1eSAndreas Gruenbacher 		bn = be64_to_cpu(*p);
14795cf26b1eSAndreas Gruenbacher 
14805cf26b1eSAndreas Gruenbacher 		if (rgd) {
14815cf26b1eSAndreas Gruenbacher 			if (!rgrp_contains_block(rgd, bn)) {
14825cf26b1eSAndreas Gruenbacher 				blks_outside_rgrp++;
14835cf26b1eSAndreas Gruenbacher 				continue;
14845cf26b1eSAndreas Gruenbacher 			}
1485d552a2b9SBob Peterson 		} else {
148690bcab99SSteven Whitehouse 			rgd = gfs2_blk2rgrpd(sdp, bn, true);
14875cf26b1eSAndreas Gruenbacher 			if (unlikely(!rgd)) {
14885cf26b1eSAndreas Gruenbacher 				ret = -EIO;
14895cf26b1eSAndreas Gruenbacher 				goto out;
14905cf26b1eSAndreas Gruenbacher 			}
1491d552a2b9SBob Peterson 			ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
14924fc7ec31SBob Peterson 						 LM_FLAG_NODE_SCOPE, rd_gh);
1493d552a2b9SBob Peterson 			if (ret)
1494d552a2b9SBob Peterson 				goto out;
1495b3b94faaSDavid Teigland 
1496d552a2b9SBob Peterson 			/* Must be done with the rgrp glock held: */
1497d552a2b9SBob Peterson 			if (gfs2_rs_active(&ip->i_res) &&
1498c65b76b8SAndreas Gruenbacher 			    rgd == ip->i_res.rs_rgd)
1499d552a2b9SBob Peterson 				gfs2_rs_deltree(&ip->i_res);
1500b3b94faaSDavid Teigland 		}
1501b3b94faaSDavid Teigland 
1502d552a2b9SBob Peterson 		/* The size of our transactions will be unknown until we
1503d552a2b9SBob Peterson 		   actually process all the metadata blocks that relate to
1504d552a2b9SBob Peterson 		   the rgrp. So we estimate. We know it can't be more than
1505d552a2b9SBob Peterson 		   the dinode's i_blocks and we don't want to exceed the
1506d552a2b9SBob Peterson 		   journal flush threshold, sd_log_thresh2. */
1507d552a2b9SBob Peterson 		if (current->journal_info == NULL) {
1508d552a2b9SBob Peterson 			unsigned int jblocks_rqsted, revokes;
1509d552a2b9SBob Peterson 
1510d552a2b9SBob Peterson 			jblocks_rqsted = rgd->rd_length + RES_DINODE +
1511d552a2b9SBob Peterson 				RES_INDIRECT;
1512d552a2b9SBob Peterson 			isize_blks = gfs2_get_inode_blocks(&ip->i_inode);
1513d552a2b9SBob Peterson 			if (isize_blks > atomic_read(&sdp->sd_log_thresh2))
1514d552a2b9SBob Peterson 				jblocks_rqsted +=
1515d552a2b9SBob Peterson 					atomic_read(&sdp->sd_log_thresh2);
1516d552a2b9SBob Peterson 			else
1517d552a2b9SBob Peterson 				jblocks_rqsted += isize_blks;
1518d552a2b9SBob Peterson 			revokes = jblocks_rqsted;
1519d552a2b9SBob Peterson 			if (meta)
15205cf26b1eSAndreas Gruenbacher 				revokes += end - start;
1521d552a2b9SBob Peterson 			else if (ip->i_depth)
1522d552a2b9SBob Peterson 				revokes += sdp->sd_inptrs;
1523d552a2b9SBob Peterson 			ret = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
1524d552a2b9SBob Peterson 			if (ret)
1525d552a2b9SBob Peterson 				goto out_unlock;
1526d552a2b9SBob Peterson 			down_write(&ip->i_rw_mutex);
1527d552a2b9SBob Peterson 		}
1528d552a2b9SBob Peterson 		/* check if we will exceed the transaction blocks requested */
1529d552a2b9SBob Peterson 		tr = current->journal_info;
1530d552a2b9SBob Peterson 		if (tr->tr_num_buf_new + RES_STATFS +
1531d552a2b9SBob Peterson 		    RES_QUOTA >= atomic_read(&sdp->sd_log_thresh2)) {
1532d552a2b9SBob Peterson 			/* We set blks_outside_rgrp to ensure the loop will
1533d552a2b9SBob Peterson 			   be repeated for the same rgrp, but with a new
1534d552a2b9SBob Peterson 			   transaction. */
1535d552a2b9SBob Peterson 			blks_outside_rgrp++;
1536d552a2b9SBob Peterson 			/* This next part is tricky. If the buffer was added
1537d552a2b9SBob Peterson 			   to the transaction, we've already set some block
1538d552a2b9SBob Peterson 			   pointers to 0, so we better follow through and free
1539d552a2b9SBob Peterson 			   them, or we will introduce corruption (so break).
1540d552a2b9SBob Peterson 			   This may be impossible, or at least rare, but I
1541d552a2b9SBob Peterson 			   decided to cover the case regardless.
1542d552a2b9SBob Peterson 
1543d552a2b9SBob Peterson 			   If the buffer was not added to the transaction
1544d552a2b9SBob Peterson 			   (this call), doing so would exceed our transaction
1545d552a2b9SBob Peterson 			   size, so we need to end the transaction and start a
1546d552a2b9SBob Peterson 			   new one (so goto). */
1547d552a2b9SBob Peterson 
1548d552a2b9SBob Peterson 			if (buf_in_tr)
1549d552a2b9SBob Peterson 				break;
1550d552a2b9SBob Peterson 			goto out_unlock;
1551d552a2b9SBob Peterson 		}
1552d552a2b9SBob Peterson 
1553d552a2b9SBob Peterson 		gfs2_trans_add_meta(ip->i_gl, bh);
1554d552a2b9SBob Peterson 		buf_in_tr = true;
1555d552a2b9SBob Peterson 		*p = 0;
1556d552a2b9SBob Peterson 		if (bstart + blen == bn) {
1557d552a2b9SBob Peterson 			blen++;
1558d552a2b9SBob Peterson 			continue;
1559d552a2b9SBob Peterson 		}
1560d552a2b9SBob Peterson 		if (bstart) {
15610ddeded4SAndreas Gruenbacher 			__gfs2_free_blocks(ip, rgd, bstart, (u32)blen, meta);
1562d552a2b9SBob Peterson 			(*btotal) += blen;
1563d552a2b9SBob Peterson 			gfs2_add_inode_blocks(&ip->i_inode, -blen);
1564d552a2b9SBob Peterson 		}
1565d552a2b9SBob Peterson 		bstart = bn;
1566d552a2b9SBob Peterson 		blen = 1;
1567d552a2b9SBob Peterson 	}
1568d552a2b9SBob Peterson 	if (bstart) {
15690ddeded4SAndreas Gruenbacher 		__gfs2_free_blocks(ip, rgd, bstart, (u32)blen, meta);
1570d552a2b9SBob Peterson 		(*btotal) += blen;
1571d552a2b9SBob Peterson 		gfs2_add_inode_blocks(&ip->i_inode, -blen);
1572d552a2b9SBob Peterson 	}
1573d552a2b9SBob Peterson out_unlock:
1574d552a2b9SBob Peterson 	if (!ret && blks_outside_rgrp) { /* If buffer still has non-zero blocks
1575d552a2b9SBob Peterson 					    outside the rgrp we just processed,
1576d552a2b9SBob Peterson 					    do it all over again. */
1577d552a2b9SBob Peterson 		if (current->journal_info) {
15785cf26b1eSAndreas Gruenbacher 			struct buffer_head *dibh;
15795cf26b1eSAndreas Gruenbacher 
15805cf26b1eSAndreas Gruenbacher 			ret = gfs2_meta_inode_buffer(ip, &dibh);
15815cf26b1eSAndreas Gruenbacher 			if (ret)
15825cf26b1eSAndreas Gruenbacher 				goto out;
1583d552a2b9SBob Peterson 
1584d552a2b9SBob Peterson 			/* Every transaction boundary, we rewrite the dinode
1585d552a2b9SBob Peterson 			   to keep its di_blocks current in case of failure. */
15868a8b8d91SJeff Layton 			ip->i_inode.i_mtime = inode_set_ctime_current(&ip->i_inode);
1587d552a2b9SBob Peterson 			gfs2_trans_add_meta(ip->i_gl, dibh);
1588d552a2b9SBob Peterson 			gfs2_dinode_out(ip, dibh->b_data);
15895cf26b1eSAndreas Gruenbacher 			brelse(dibh);
1590d552a2b9SBob Peterson 			up_write(&ip->i_rw_mutex);
1591d552a2b9SBob Peterson 			gfs2_trans_end(sdp);
1592f0b444b3SBob Peterson 			buf_in_tr = false;
1593d552a2b9SBob Peterson 		}
1594d552a2b9SBob Peterson 		gfs2_glock_dq_uninit(rd_gh);
1595d552a2b9SBob Peterson 		cond_resched();
1596d552a2b9SBob Peterson 		goto more_rgrps;
1597d552a2b9SBob Peterson 	}
1598d552a2b9SBob Peterson out:
1599d552a2b9SBob Peterson 	return ret;
1600d552a2b9SBob Peterson }
1601d552a2b9SBob Peterson 
mp_eq_to_hgt(struct metapath * mp,__u16 * list,unsigned int h)160210d2cf94SAndreas Gruenbacher static bool mp_eq_to_hgt(struct metapath *mp, __u16 *list, unsigned int h)
160310d2cf94SAndreas Gruenbacher {
160410d2cf94SAndreas Gruenbacher 	if (memcmp(mp->mp_list, list, h * sizeof(mp->mp_list[0])))
160510d2cf94SAndreas Gruenbacher 		return false;
160610d2cf94SAndreas Gruenbacher 	return true;
160710d2cf94SAndreas Gruenbacher }
160810d2cf94SAndreas Gruenbacher 
1609d552a2b9SBob Peterson /**
1610d552a2b9SBob Peterson  * find_nonnull_ptr - find a non-null pointer given a metapath and height
1611c551f66cSLee Jones  * @sdp: The superblock
1612d552a2b9SBob Peterson  * @mp: starting metapath
1613d552a2b9SBob Peterson  * @h: desired height to search
1614c551f66cSLee Jones  * @end_list: See punch_hole().
1615c551f66cSLee Jones  * @end_aligned: See punch_hole().
1616d552a2b9SBob Peterson  *
161710d2cf94SAndreas Gruenbacher  * Assumes the metapath is valid (with buffers) out to height h.
1618d552a2b9SBob Peterson  * Returns: true if a non-null pointer was found in the metapath buffer
1619d552a2b9SBob Peterson  *          false if all remaining pointers are NULL in the buffer
1620d552a2b9SBob Peterson  */
find_nonnull_ptr(struct gfs2_sbd * sdp,struct metapath * mp,unsigned int h,__u16 * end_list,unsigned int end_aligned)1621d552a2b9SBob Peterson static bool find_nonnull_ptr(struct gfs2_sbd *sdp, struct metapath *mp,
162210d2cf94SAndreas Gruenbacher 			     unsigned int h,
162310d2cf94SAndreas Gruenbacher 			     __u16 *end_list, unsigned int end_aligned)
1624d552a2b9SBob Peterson {
162510d2cf94SAndreas Gruenbacher 	struct buffer_head *bh = mp->mp_bh[h];
162610d2cf94SAndreas Gruenbacher 	__be64 *first, *ptr, *end;
1627d552a2b9SBob Peterson 
162810d2cf94SAndreas Gruenbacher 	first = metaptr1(h, mp);
162910d2cf94SAndreas Gruenbacher 	ptr = first + mp->mp_list[h];
163010d2cf94SAndreas Gruenbacher 	end = (__be64 *)(bh->b_data + bh->b_size);
163110d2cf94SAndreas Gruenbacher 	if (end_list && mp_eq_to_hgt(mp, end_list, h)) {
163210d2cf94SAndreas Gruenbacher 		bool keep_end = h < end_aligned;
163310d2cf94SAndreas Gruenbacher 		end = first + end_list[h] + keep_end;
163410d2cf94SAndreas Gruenbacher 	}
163510d2cf94SAndreas Gruenbacher 
163610d2cf94SAndreas Gruenbacher 	while (ptr < end) {
1637c4a9d189SBob Peterson 		if (*ptr) { /* if we have a non-null pointer */
163810d2cf94SAndreas Gruenbacher 			mp->mp_list[h] = ptr - first;
1639c4a9d189SBob Peterson 			h++;
1640c4a9d189SBob Peterson 			if (h < GFS2_MAX_META_HEIGHT)
164110d2cf94SAndreas Gruenbacher 				mp->mp_list[h] = 0;
1642d552a2b9SBob Peterson 			return true;
1643c4a9d189SBob Peterson 		}
164410d2cf94SAndreas Gruenbacher 		ptr++;
1645d552a2b9SBob Peterson 	}
164610d2cf94SAndreas Gruenbacher 	return false;
1647d552a2b9SBob Peterson }
1648d552a2b9SBob Peterson 
1649d552a2b9SBob Peterson enum dealloc_states {
1650d552a2b9SBob Peterson 	DEALLOC_MP_FULL = 0,    /* Strip a metapath with all buffers read in */
1651d552a2b9SBob Peterson 	DEALLOC_MP_LOWER = 1,   /* lower the metapath strip height */
1652d552a2b9SBob Peterson 	DEALLOC_FILL_MP = 2,  /* Fill in the metapath to the given height. */
1653d552a2b9SBob Peterson 	DEALLOC_DONE = 3,       /* process complete */
1654d552a2b9SBob Peterson };
1655d552a2b9SBob Peterson 
16565cf26b1eSAndreas Gruenbacher static inline void
metapointer_range(struct metapath * mp,int height,__u16 * start_list,unsigned int start_aligned,__u16 * end_list,unsigned int end_aligned,__be64 ** start,__be64 ** end)16575cf26b1eSAndreas Gruenbacher metapointer_range(struct metapath *mp, int height,
16585cf26b1eSAndreas Gruenbacher 		  __u16 *start_list, unsigned int start_aligned,
165910d2cf94SAndreas Gruenbacher 		  __u16 *end_list, unsigned int end_aligned,
16605cf26b1eSAndreas Gruenbacher 		  __be64 **start, __be64 **end)
16615cf26b1eSAndreas Gruenbacher {
16625cf26b1eSAndreas Gruenbacher 	struct buffer_head *bh = mp->mp_bh[height];
16635cf26b1eSAndreas Gruenbacher 	__be64 *first;
16645cf26b1eSAndreas Gruenbacher 
16655cf26b1eSAndreas Gruenbacher 	first = metaptr1(height, mp);
16665cf26b1eSAndreas Gruenbacher 	*start = first;
16675cf26b1eSAndreas Gruenbacher 	if (mp_eq_to_hgt(mp, start_list, height)) {
16685cf26b1eSAndreas Gruenbacher 		bool keep_start = height < start_aligned;
16695cf26b1eSAndreas Gruenbacher 		*start = first + start_list[height] + keep_start;
16705cf26b1eSAndreas Gruenbacher 	}
16715cf26b1eSAndreas Gruenbacher 	*end = (__be64 *)(bh->b_data + bh->b_size);
167210d2cf94SAndreas Gruenbacher 	if (end_list && mp_eq_to_hgt(mp, end_list, height)) {
167310d2cf94SAndreas Gruenbacher 		bool keep_end = height < end_aligned;
167410d2cf94SAndreas Gruenbacher 		*end = first + end_list[height] + keep_end;
167510d2cf94SAndreas Gruenbacher 	}
167610d2cf94SAndreas Gruenbacher }
167710d2cf94SAndreas Gruenbacher 
walk_done(struct gfs2_sbd * sdp,struct metapath * mp,int height,__u16 * end_list,unsigned int end_aligned)167810d2cf94SAndreas Gruenbacher static inline bool walk_done(struct gfs2_sbd *sdp,
167910d2cf94SAndreas Gruenbacher 			     struct metapath *mp, int height,
168010d2cf94SAndreas Gruenbacher 			     __u16 *end_list, unsigned int end_aligned)
168110d2cf94SAndreas Gruenbacher {
168210d2cf94SAndreas Gruenbacher 	__u16 end;
168310d2cf94SAndreas Gruenbacher 
168410d2cf94SAndreas Gruenbacher 	if (end_list) {
168510d2cf94SAndreas Gruenbacher 		bool keep_end = height < end_aligned;
168610d2cf94SAndreas Gruenbacher 		if (!mp_eq_to_hgt(mp, end_list, height))
168710d2cf94SAndreas Gruenbacher 			return false;
168810d2cf94SAndreas Gruenbacher 		end = end_list[height] + keep_end;
168910d2cf94SAndreas Gruenbacher 	} else
169010d2cf94SAndreas Gruenbacher 		end = (height > 0) ? sdp->sd_inptrs : sdp->sd_diptrs;
169110d2cf94SAndreas Gruenbacher 	return mp->mp_list[height] >= end;
16925cf26b1eSAndreas Gruenbacher }
16935cf26b1eSAndreas Gruenbacher 
1694d552a2b9SBob Peterson /**
169510d2cf94SAndreas Gruenbacher  * punch_hole - deallocate blocks in a file
1696d552a2b9SBob Peterson  * @ip: inode to truncate
169710d2cf94SAndreas Gruenbacher  * @offset: the start of the hole
169810d2cf94SAndreas Gruenbacher  * @length: the size of the hole (or 0 for truncate)
1699d552a2b9SBob Peterson  *
170010d2cf94SAndreas Gruenbacher  * Punch a hole into a file or truncate a file at a given position.  This
170110d2cf94SAndreas Gruenbacher  * function operates in whole blocks (@offset and @length are rounded
170210d2cf94SAndreas Gruenbacher  * accordingly); partially filled blocks must be cleared otherwise.
170310d2cf94SAndreas Gruenbacher  *
170410d2cf94SAndreas Gruenbacher  * This function works from the bottom up, and from the right to the left. In
170510d2cf94SAndreas Gruenbacher  * other words, it strips off the highest layer (data) before stripping any of
170610d2cf94SAndreas Gruenbacher  * the metadata. Doing it this way is best in case the operation is interrupted
170710d2cf94SAndreas Gruenbacher  * by power failure, etc.  The dinode is rewritten in every transaction to
170810d2cf94SAndreas Gruenbacher  * guarantee integrity.
1709d552a2b9SBob Peterson  */
punch_hole(struct gfs2_inode * ip,u64 offset,u64 length)171010d2cf94SAndreas Gruenbacher static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)
1711d552a2b9SBob Peterson {
1712d552a2b9SBob Peterson 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
1713bb491ce6SAndreas Gruenbacher 	u64 maxsize = sdp->sd_heightsize[ip->i_height];
171410d2cf94SAndreas Gruenbacher 	struct metapath mp = {};
1715d552a2b9SBob Peterson 	struct buffer_head *dibh, *bh;
1716d552a2b9SBob Peterson 	struct gfs2_holder rd_gh;
1717cb7f0903SAndreas Gruenbacher 	unsigned int bsize_shift = sdp->sd_sb.sb_bsize_shift;
17186eb0d6e6SAndrew Price 	unsigned int bsize = 1 << bsize_shift;
17196eb0d6e6SAndrew Price 	u64 lblock = (offset + bsize - 1) >> bsize_shift;
172010d2cf94SAndreas Gruenbacher 	__u16 start_list[GFS2_MAX_META_HEIGHT];
172110d2cf94SAndreas Gruenbacher 	__u16 __end_list[GFS2_MAX_META_HEIGHT], *end_list = NULL;
17223f649ab7SKees Cook 	unsigned int start_aligned, end_aligned;
1723d552a2b9SBob Peterson 	unsigned int strip_h = ip->i_height - 1;
1724d552a2b9SBob Peterson 	u32 btotal = 0;
1725d552a2b9SBob Peterson 	int ret, state;
1726d552a2b9SBob Peterson 	int mp_h; /* metapath buffers are read in to this height */
1727d552a2b9SBob Peterson 	u64 prev_bnr = 0;
17285cf26b1eSAndreas Gruenbacher 	__be64 *start, *end;
1729d552a2b9SBob Peterson 
17306eb0d6e6SAndrew Price 	if (offset + bsize - 1 >= maxsize) {
1731bb491ce6SAndreas Gruenbacher 		/*
1732e4f82bf2SBob Peterson 		 * The starting point lies beyond the allocated metadata;
1733e4f82bf2SBob Peterson 		 * there are no blocks to deallocate.
1734bb491ce6SAndreas Gruenbacher 		 */
1735bb491ce6SAndreas Gruenbacher 		return 0;
1736bb491ce6SAndreas Gruenbacher 	}
1737bb491ce6SAndreas Gruenbacher 
173810d2cf94SAndreas Gruenbacher 	/*
173910d2cf94SAndreas Gruenbacher 	 * The start position of the hole is defined by lblock, start_list, and
174010d2cf94SAndreas Gruenbacher 	 * start_aligned.  The end position of the hole is defined by lend,
174110d2cf94SAndreas Gruenbacher 	 * end_list, and end_aligned.
174210d2cf94SAndreas Gruenbacher 	 *
174310d2cf94SAndreas Gruenbacher 	 * start_aligned and end_aligned define down to which height the start
174410d2cf94SAndreas Gruenbacher 	 * and end positions are aligned to the metadata tree (i.e., the
174510d2cf94SAndreas Gruenbacher 	 * position is a multiple of the metadata granularity at the height
174610d2cf94SAndreas Gruenbacher 	 * above).  This determines at which heights additional meta pointers
174710d2cf94SAndreas Gruenbacher 	 * needs to be preserved for the remaining data.
174810d2cf94SAndreas Gruenbacher 	 */
1749d552a2b9SBob Peterson 
175010d2cf94SAndreas Gruenbacher 	if (length) {
175110d2cf94SAndreas Gruenbacher 		u64 end_offset = offset + length;
175210d2cf94SAndreas Gruenbacher 		u64 lend;
1753cb7f0903SAndreas Gruenbacher 
1754cb7f0903SAndreas Gruenbacher 		/*
175510d2cf94SAndreas Gruenbacher 		 * Clip the end at the maximum file size for the given height:
175610d2cf94SAndreas Gruenbacher 		 * that's how far the metadata goes; files bigger than that
175710d2cf94SAndreas Gruenbacher 		 * will have additional layers of indirection.
1758cb7f0903SAndreas Gruenbacher 		 */
175910d2cf94SAndreas Gruenbacher 		if (end_offset > maxsize)
176010d2cf94SAndreas Gruenbacher 			end_offset = maxsize;
176110d2cf94SAndreas Gruenbacher 		lend = end_offset >> bsize_shift;
176210d2cf94SAndreas Gruenbacher 
176310d2cf94SAndreas Gruenbacher 		if (lblock >= lend)
176410d2cf94SAndreas Gruenbacher 			return 0;
176510d2cf94SAndreas Gruenbacher 
176610d2cf94SAndreas Gruenbacher 		find_metapath(sdp, lend, &mp, ip->i_height);
176710d2cf94SAndreas Gruenbacher 		end_list = __end_list;
176810d2cf94SAndreas Gruenbacher 		memcpy(end_list, mp.mp_list, sizeof(mp.mp_list));
176910d2cf94SAndreas Gruenbacher 
177010d2cf94SAndreas Gruenbacher 		for (mp_h = ip->i_height - 1; mp_h > 0; mp_h--) {
177110d2cf94SAndreas Gruenbacher 			if (end_list[mp_h])
177210d2cf94SAndreas Gruenbacher 				break;
177310d2cf94SAndreas Gruenbacher 		}
177410d2cf94SAndreas Gruenbacher 		end_aligned = mp_h;
177510d2cf94SAndreas Gruenbacher 	}
177610d2cf94SAndreas Gruenbacher 
177710d2cf94SAndreas Gruenbacher 	find_metapath(sdp, lblock, &mp, ip->i_height);
177810d2cf94SAndreas Gruenbacher 	memcpy(start_list, mp.mp_list, sizeof(start_list));
177910d2cf94SAndreas Gruenbacher 
1780cb7f0903SAndreas Gruenbacher 	for (mp_h = ip->i_height - 1; mp_h > 0; mp_h--) {
1781cb7f0903SAndreas Gruenbacher 		if (start_list[mp_h])
1782cb7f0903SAndreas Gruenbacher 			break;
1783cb7f0903SAndreas Gruenbacher 	}
1784cb7f0903SAndreas Gruenbacher 	start_aligned = mp_h;
1785d552a2b9SBob Peterson 
1786d552a2b9SBob Peterson 	ret = gfs2_meta_inode_buffer(ip, &dibh);
1787d552a2b9SBob Peterson 	if (ret)
1788d552a2b9SBob Peterson 		return ret;
1789d552a2b9SBob Peterson 
1790d552a2b9SBob Peterson 	mp.mp_bh[0] = dibh;
1791d552a2b9SBob Peterson 	ret = lookup_metapath(ip, &mp);
1792e8b43fe0SAndreas Gruenbacher 	if (ret)
1793e8b43fe0SAndreas Gruenbacher 		goto out_metapath;
1794c3ce5aa9SAndreas Gruenbacher 
1795c3ce5aa9SAndreas Gruenbacher 	/* issue read-ahead on metadata */
17965cf26b1eSAndreas Gruenbacher 	for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++) {
17975cf26b1eSAndreas Gruenbacher 		metapointer_range(&mp, mp_h, start_list, start_aligned,
179810d2cf94SAndreas Gruenbacher 				  end_list, end_aligned, &start, &end);
17995cf26b1eSAndreas Gruenbacher 		gfs2_metapath_ra(ip->i_gl, start, end);
18005cf26b1eSAndreas Gruenbacher 	}
1801c3ce5aa9SAndreas Gruenbacher 
1802e8b43fe0SAndreas Gruenbacher 	if (mp.mp_aheight == ip->i_height)
1803d552a2b9SBob Peterson 		state = DEALLOC_MP_FULL; /* We have a complete metapath */
1804d552a2b9SBob Peterson 	else
1805d552a2b9SBob Peterson 		state = DEALLOC_FILL_MP; /* deal with partial metapath */
1806d552a2b9SBob Peterson 
1807d552a2b9SBob Peterson 	ret = gfs2_rindex_update(sdp);
1808d552a2b9SBob Peterson 	if (ret)
1809d552a2b9SBob Peterson 		goto out_metapath;
1810d552a2b9SBob Peterson 
1811d552a2b9SBob Peterson 	ret = gfs2_quota_hold(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);
1812d552a2b9SBob Peterson 	if (ret)
1813d552a2b9SBob Peterson 		goto out_metapath;
1814d552a2b9SBob Peterson 	gfs2_holder_mark_uninitialized(&rd_gh);
1815d552a2b9SBob Peterson 
1816d552a2b9SBob Peterson 	mp_h = strip_h;
1817d552a2b9SBob Peterson 
1818d552a2b9SBob Peterson 	while (state != DEALLOC_DONE) {
1819d552a2b9SBob Peterson 		switch (state) {
1820d552a2b9SBob Peterson 		/* Truncate a full metapath at the given strip height.
1821d552a2b9SBob Peterson 		 * Note that strip_h == mp_h in order to be in this state. */
1822d552a2b9SBob Peterson 		case DEALLOC_MP_FULL:
1823d552a2b9SBob Peterson 			bh = mp.mp_bh[mp_h];
1824d552a2b9SBob Peterson 			gfs2_assert_withdraw(sdp, bh);
1825d552a2b9SBob Peterson 			if (gfs2_assert_withdraw(sdp,
1826d552a2b9SBob Peterson 						 prev_bnr != bh->b_blocknr)) {
1827f29e62eeSBob Peterson 				fs_emerg(sdp, "inode %llu, block:%llu, i_h:%u,"
1828f29e62eeSBob Peterson 					 "s_h:%u, mp_h:%u\n",
1829d552a2b9SBob Peterson 				       (unsigned long long)ip->i_no_addr,
1830d552a2b9SBob Peterson 				       prev_bnr, ip->i_height, strip_h, mp_h);
1831d552a2b9SBob Peterson 			}
1832d552a2b9SBob Peterson 			prev_bnr = bh->b_blocknr;
1833cb7f0903SAndreas Gruenbacher 
18345cf26b1eSAndreas Gruenbacher 			if (gfs2_metatype_check(sdp, bh,
18355cf26b1eSAndreas Gruenbacher 						(mp_h ? GFS2_METATYPE_IN :
18365cf26b1eSAndreas Gruenbacher 							GFS2_METATYPE_DI))) {
18375cf26b1eSAndreas Gruenbacher 				ret = -EIO;
18385cf26b1eSAndreas Gruenbacher 				goto out;
18395cf26b1eSAndreas Gruenbacher 			}
1840cb7f0903SAndreas Gruenbacher 
184110d2cf94SAndreas Gruenbacher 			/*
184210d2cf94SAndreas Gruenbacher 			 * Below, passing end_aligned as 0 gives us the
184310d2cf94SAndreas Gruenbacher 			 * metapointer range excluding the end point: the end
184410d2cf94SAndreas Gruenbacher 			 * point is the first metapath we must not deallocate!
184510d2cf94SAndreas Gruenbacher 			 */
184610d2cf94SAndreas Gruenbacher 
18475cf26b1eSAndreas Gruenbacher 			metapointer_range(&mp, mp_h, start_list, start_aligned,
184810d2cf94SAndreas Gruenbacher 					  end_list, 0 /* end_aligned */,
18495cf26b1eSAndreas Gruenbacher 					  &start, &end);
18505cf26b1eSAndreas Gruenbacher 			ret = sweep_bh_for_rgrps(ip, &rd_gh, mp.mp_bh[mp_h],
18515cf26b1eSAndreas Gruenbacher 						 start, end,
18525cf26b1eSAndreas Gruenbacher 						 mp_h != ip->i_height - 1,
18535cf26b1eSAndreas Gruenbacher 						 &btotal);
18545cf26b1eSAndreas Gruenbacher 
1855d552a2b9SBob Peterson 			/* If we hit an error or just swept dinode buffer,
1856d552a2b9SBob Peterson 			   just exit. */
1857d552a2b9SBob Peterson 			if (ret || !mp_h) {
1858d552a2b9SBob Peterson 				state = DEALLOC_DONE;
1859d552a2b9SBob Peterson 				break;
1860d552a2b9SBob Peterson 			}
1861d552a2b9SBob Peterson 			state = DEALLOC_MP_LOWER;
1862d552a2b9SBob Peterson 			break;
1863d552a2b9SBob Peterson 
1864d552a2b9SBob Peterson 		/* lower the metapath strip height */
1865d552a2b9SBob Peterson 		case DEALLOC_MP_LOWER:
1866d552a2b9SBob Peterson 			/* We're done with the current buffer, so release it,
1867d552a2b9SBob Peterson 			   unless it's the dinode buffer. Then back up to the
1868d552a2b9SBob Peterson 			   previous pointer. */
1869d552a2b9SBob Peterson 			if (mp_h) {
1870d552a2b9SBob Peterson 				brelse(mp.mp_bh[mp_h]);
1871d552a2b9SBob Peterson 				mp.mp_bh[mp_h] = NULL;
1872d552a2b9SBob Peterson 			}
1873d552a2b9SBob Peterson 			/* If we can't get any lower in height, we've stripped
1874d552a2b9SBob Peterson 			   off all we can. Next step is to back up and start
1875d552a2b9SBob Peterson 			   stripping the previous level of metadata. */
1876d552a2b9SBob Peterson 			if (mp_h == 0) {
1877d552a2b9SBob Peterson 				strip_h--;
1878cb7f0903SAndreas Gruenbacher 				memcpy(mp.mp_list, start_list, sizeof(start_list));
1879d552a2b9SBob Peterson 				mp_h = strip_h;
1880d552a2b9SBob Peterson 				state = DEALLOC_FILL_MP;
1881d552a2b9SBob Peterson 				break;
1882d552a2b9SBob Peterson 			}
1883d552a2b9SBob Peterson 			mp.mp_list[mp_h] = 0;
1884d552a2b9SBob Peterson 			mp_h--; /* search one metadata height down */
1885d552a2b9SBob Peterson 			mp.mp_list[mp_h]++;
188610d2cf94SAndreas Gruenbacher 			if (walk_done(sdp, &mp, mp_h, end_list, end_aligned))
188710d2cf94SAndreas Gruenbacher 				break;
1888d552a2b9SBob Peterson 			/* Here we've found a part of the metapath that is not
1889d552a2b9SBob Peterson 			 * allocated. We need to search at that height for the
1890d552a2b9SBob Peterson 			 * next non-null pointer. */
189110d2cf94SAndreas Gruenbacher 			if (find_nonnull_ptr(sdp, &mp, mp_h, end_list, end_aligned)) {
1892d552a2b9SBob Peterson 				state = DEALLOC_FILL_MP;
1893d552a2b9SBob Peterson 				mp_h++;
1894d552a2b9SBob Peterson 			}
1895d552a2b9SBob Peterson 			/* No more non-null pointers at this height. Back up
1896d552a2b9SBob Peterson 			   to the previous height and try again. */
1897d552a2b9SBob Peterson 			break; /* loop around in the same state */
1898d552a2b9SBob Peterson 
1899d552a2b9SBob Peterson 		/* Fill the metapath with buffers to the given height. */
1900d552a2b9SBob Peterson 		case DEALLOC_FILL_MP:
1901d552a2b9SBob Peterson 			/* Fill the buffers out to the current height. */
1902d552a2b9SBob Peterson 			ret = fillup_metapath(ip, &mp, mp_h);
1903c3ce5aa9SAndreas Gruenbacher 			if (ret < 0)
1904d552a2b9SBob Peterson 				goto out;
1905d552a2b9SBob Peterson 
1906e7445cedSAndreas Gruenbacher 			/* On the first pass, issue read-ahead on metadata. */
1907e7445cedSAndreas Gruenbacher 			if (mp.mp_aheight > 1 && strip_h == ip->i_height - 1) {
1908e7445cedSAndreas Gruenbacher 				unsigned int height = mp.mp_aheight - 1;
1909e7445cedSAndreas Gruenbacher 
1910e7445cedSAndreas Gruenbacher 				/* No read-ahead for data blocks. */
1911e7445cedSAndreas Gruenbacher 				if (mp.mp_aheight - 1 == strip_h)
1912e7445cedSAndreas Gruenbacher 					height--;
1913e7445cedSAndreas Gruenbacher 
1914e7445cedSAndreas Gruenbacher 				for (; height >= mp.mp_aheight - ret; height--) {
1915e7445cedSAndreas Gruenbacher 					metapointer_range(&mp, height,
19165cf26b1eSAndreas Gruenbacher 							  start_list, start_aligned,
191710d2cf94SAndreas Gruenbacher 							  end_list, end_aligned,
19185cf26b1eSAndreas Gruenbacher 							  &start, &end);
19195cf26b1eSAndreas Gruenbacher 					gfs2_metapath_ra(ip->i_gl, start, end);
19205cf26b1eSAndreas Gruenbacher 				}
1921c3ce5aa9SAndreas Gruenbacher 			}
1922c3ce5aa9SAndreas Gruenbacher 
1923d552a2b9SBob Peterson 			/* If buffers found for the entire strip height */
1924e8b43fe0SAndreas Gruenbacher 			if (mp.mp_aheight - 1 == strip_h) {
1925d552a2b9SBob Peterson 				state = DEALLOC_MP_FULL;
1926d552a2b9SBob Peterson 				break;
1927d552a2b9SBob Peterson 			}
1928e8b43fe0SAndreas Gruenbacher 			if (mp.mp_aheight < ip->i_height) /* We have a partial height */
1929e8b43fe0SAndreas Gruenbacher 				mp_h = mp.mp_aheight - 1;
1930d552a2b9SBob Peterson 
1931d552a2b9SBob Peterson 			/* If we find a non-null block pointer, crawl a bit
1932d552a2b9SBob Peterson 			   higher up in the metapath and try again, otherwise
1933d552a2b9SBob Peterson 			   we need to look lower for a new starting point. */
193410d2cf94SAndreas Gruenbacher 			if (find_nonnull_ptr(sdp, &mp, mp_h, end_list, end_aligned))
1935d552a2b9SBob Peterson 				mp_h++;
1936d552a2b9SBob Peterson 			else
1937d552a2b9SBob Peterson 				state = DEALLOC_MP_LOWER;
1938d552a2b9SBob Peterson 			break;
1939d552a2b9SBob Peterson 		}
1940d552a2b9SBob Peterson 	}
1941d552a2b9SBob Peterson 
1942d552a2b9SBob Peterson 	if (btotal) {
1943d552a2b9SBob Peterson 		if (current->journal_info == NULL) {
1944d552a2b9SBob Peterson 			ret = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS +
1945d552a2b9SBob Peterson 					       RES_QUOTA, 0);
1946d552a2b9SBob Peterson 			if (ret)
1947d552a2b9SBob Peterson 				goto out;
1948d552a2b9SBob Peterson 			down_write(&ip->i_rw_mutex);
1949d552a2b9SBob Peterson 		}
1950d552a2b9SBob Peterson 		gfs2_statfs_change(sdp, 0, +btotal, 0);
1951d552a2b9SBob Peterson 		gfs2_quota_change(ip, -(s64)btotal, ip->i_inode.i_uid,
1952d552a2b9SBob Peterson 				  ip->i_inode.i_gid);
19538a8b8d91SJeff Layton 		ip->i_inode.i_mtime = inode_set_ctime_current(&ip->i_inode);
1954d552a2b9SBob Peterson 		gfs2_trans_add_meta(ip->i_gl, dibh);
1955d552a2b9SBob Peterson 		gfs2_dinode_out(ip, dibh->b_data);
1956d552a2b9SBob Peterson 		up_write(&ip->i_rw_mutex);
1957d552a2b9SBob Peterson 		gfs2_trans_end(sdp);
1958d552a2b9SBob Peterson 	}
1959d552a2b9SBob Peterson 
1960d552a2b9SBob Peterson out:
1961d552a2b9SBob Peterson 	if (gfs2_holder_initialized(&rd_gh))
1962d552a2b9SBob Peterson 		gfs2_glock_dq_uninit(&rd_gh);
1963d552a2b9SBob Peterson 	if (current->journal_info) {
1964d552a2b9SBob Peterson 		up_write(&ip->i_rw_mutex);
1965d552a2b9SBob Peterson 		gfs2_trans_end(sdp);
1966d552a2b9SBob Peterson 		cond_resched();
1967d552a2b9SBob Peterson 	}
1968d552a2b9SBob Peterson 	gfs2_quota_unhold(ip);
1969d552a2b9SBob Peterson out_metapath:
1970d552a2b9SBob Peterson 	release_metapath(&mp);
1971d552a2b9SBob Peterson 	return ret;
1972b3b94faaSDavid Teigland }
1973b3b94faaSDavid Teigland 
trunc_end(struct gfs2_inode * ip)1974b3b94faaSDavid Teigland static int trunc_end(struct gfs2_inode *ip)
1975b3b94faaSDavid Teigland {
1976feaa7bbaSSteven Whitehouse 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
1977b3b94faaSDavid Teigland 	struct buffer_head *dibh;
1978b3b94faaSDavid Teigland 	int error;
1979b3b94faaSDavid Teigland 
1980b3b94faaSDavid Teigland 	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
1981b3b94faaSDavid Teigland 	if (error)
1982b3b94faaSDavid Teigland 		return error;
1983b3b94faaSDavid Teigland 
1984b3b94faaSDavid Teigland 	down_write(&ip->i_rw_mutex);
1985b3b94faaSDavid Teigland 
1986b3b94faaSDavid Teigland 	error = gfs2_meta_inode_buffer(ip, &dibh);
1987b3b94faaSDavid Teigland 	if (error)
1988b3b94faaSDavid Teigland 		goto out;
1989b3b94faaSDavid Teigland 
1990a2e0f799SSteven Whitehouse 	if (!i_size_read(&ip->i_inode)) {
1991ecc30c79SSteven Whitehouse 		ip->i_height = 0;
1992ce276b06SSteven Whitehouse 		ip->i_goal = ip->i_no_addr;
1993b3b94faaSDavid Teigland 		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
199445138990SSteven Whitehouse 		gfs2_ordered_del_inode(ip);
1995b3b94faaSDavid Teigland 	}
19968a8b8d91SJeff Layton 	ip->i_inode.i_mtime = inode_set_ctime_current(&ip->i_inode);
1997383f01fbSSteven Whitehouse 	ip->i_diskflags &= ~GFS2_DIF_TRUNC_IN_PROG;
1998b3b94faaSDavid Teigland 
1999350a9b0aSSteven Whitehouse 	gfs2_trans_add_meta(ip->i_gl, dibh);
2000539e5d6bSSteven Whitehouse 	gfs2_dinode_out(ip, dibh->b_data);
2001b3b94faaSDavid Teigland 	brelse(dibh);
2002b3b94faaSDavid Teigland 
2003b3b94faaSDavid Teigland out:
2004b3b94faaSDavid Teigland 	up_write(&ip->i_rw_mutex);
2005b3b94faaSDavid Teigland 	gfs2_trans_end(sdp);
2006b3b94faaSDavid Teigland 	return error;
2007b3b94faaSDavid Teigland }
2008b3b94faaSDavid Teigland 
2009b3b94faaSDavid Teigland /**
2010b3b94faaSDavid Teigland  * do_shrink - make a file smaller
2011ff8f33c8SSteven Whitehouse  * @inode: the inode
2012ff8f33c8SSteven Whitehouse  * @newsize: the size to make the file
2013b3b94faaSDavid Teigland  *
2014ff8f33c8SSteven Whitehouse  * Called with an exclusive lock on @inode. The @size must
2015ff8f33c8SSteven Whitehouse  * be equal to or smaller than the current inode size.
2016b3b94faaSDavid Teigland  *
2017b3b94faaSDavid Teigland  * Returns: errno
2018b3b94faaSDavid Teigland  */
2019b3b94faaSDavid Teigland 
do_shrink(struct inode * inode,u64 newsize)20208b5860a3SAndreas Gruenbacher static int do_shrink(struct inode *inode, u64 newsize)
2021b3b94faaSDavid Teigland {
2022ff8f33c8SSteven Whitehouse 	struct gfs2_inode *ip = GFS2_I(inode);
2023b3b94faaSDavid Teigland 	int error;
2024b3b94faaSDavid Teigland 
20258b5860a3SAndreas Gruenbacher 	error = trunc_start(inode, newsize);
2026b3b94faaSDavid Teigland 	if (error < 0)
2027b3b94faaSDavid Teigland 		return error;
2028ff8f33c8SSteven Whitehouse 	if (gfs2_is_stuffed(ip))
2029b3b94faaSDavid Teigland 		return 0;
2030b3b94faaSDavid Teigland 
203110d2cf94SAndreas Gruenbacher 	error = punch_hole(ip, newsize, 0);
2032ff8f33c8SSteven Whitehouse 	if (error == 0)
2033b3b94faaSDavid Teigland 		error = trunc_end(ip);
2034b3b94faaSDavid Teigland 
2035b3b94faaSDavid Teigland 	return error;
2036b3b94faaSDavid Teigland }
2037b3b94faaSDavid Teigland 
2038ff8f33c8SSteven Whitehouse /**
2039ff8f33c8SSteven Whitehouse  * do_grow - Touch and update inode size
2040ff8f33c8SSteven Whitehouse  * @inode: The inode
2041ff8f33c8SSteven Whitehouse  * @size: The new size
2042ff8f33c8SSteven Whitehouse  *
2043ff8f33c8SSteven Whitehouse  * This function updates the timestamps on the inode and
2044ff8f33c8SSteven Whitehouse  * may also increase the size of the inode. This function
2045ff8f33c8SSteven Whitehouse  * must not be called with @size any smaller than the current
2046ff8f33c8SSteven Whitehouse  * inode size.
2047ff8f33c8SSteven Whitehouse  *
2048ff8f33c8SSteven Whitehouse  * Although it is not strictly required to unstuff files here,
2049ff8f33c8SSteven Whitehouse  * earlier versions of GFS2 have a bug in the stuffed file reading
2050ff8f33c8SSteven Whitehouse  * code which will result in a buffer overrun if the size is larger
2051ff8f33c8SSteven Whitehouse  * than the max stuffed file size. In order to prevent this from
205225985edcSLucas De Marchi  * occurring, such files are unstuffed, but in other cases we can
2053ff8f33c8SSteven Whitehouse  * just update the inode size directly.
2054ff8f33c8SSteven Whitehouse  *
2055ff8f33c8SSteven Whitehouse  * Returns: 0 on success, or -ve on error
2056ff8f33c8SSteven Whitehouse  */
2057ff8f33c8SSteven Whitehouse 
do_grow(struct inode * inode,u64 size)2058ff8f33c8SSteven Whitehouse static int do_grow(struct inode *inode, u64 size)
2059ff8f33c8SSteven Whitehouse {
2060ff8f33c8SSteven Whitehouse 	struct gfs2_inode *ip = GFS2_I(inode);
2061ff8f33c8SSteven Whitehouse 	struct gfs2_sbd *sdp = GFS2_SB(inode);
20627b9cff46SSteven Whitehouse 	struct gfs2_alloc_parms ap = { .target = 1, };
2063a13b8c5fSWendy Cheng 	struct buffer_head *dibh;
2064a13b8c5fSWendy Cheng 	int error;
20652f7ee358SBob Peterson 	int unstuff = 0;
2066a13b8c5fSWendy Cheng 
2067235628c5SAndreas Gruenbacher 	if (gfs2_is_stuffed(ip) && size > gfs2_max_stuffed_size(ip)) {
2068b8fbf471SAbhi Das 		error = gfs2_quota_lock_check(ip, &ap);
2069ff8f33c8SSteven Whitehouse 		if (error)
20705407e242SBob Peterson 			return error;
2071ff8f33c8SSteven Whitehouse 
20727b9cff46SSteven Whitehouse 		error = gfs2_inplace_reserve(ip, &ap);
2073ff8f33c8SSteven Whitehouse 		if (error)
2074ff8f33c8SSteven Whitehouse 			goto do_grow_qunlock;
20752f7ee358SBob Peterson 		unstuff = 1;
2076ff8f33c8SSteven Whitehouse 	}
2077ff8f33c8SSteven Whitehouse 
2078a01aedfeSBob Peterson 	error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT +
2079bc020561SBob Peterson 				 (unstuff &&
2080bc020561SBob Peterson 				  gfs2_is_jdata(ip) ? RES_JDATA : 0) +
2081a01aedfeSBob Peterson 				 (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF ?
2082a01aedfeSBob Peterson 				  0 : RES_QUOTA), 0);
2083ff8f33c8SSteven Whitehouse 	if (error)
2084ff8f33c8SSteven Whitehouse 		goto do_grow_release;
2085ff8f33c8SSteven Whitehouse 
20862f7ee358SBob Peterson 	if (unstuff) {
20877a607a41SAndreas Gruenbacher 		error = gfs2_unstuff_dinode(ip);
2088ff8f33c8SSteven Whitehouse 		if (error)
2089ff8f33c8SSteven Whitehouse 			goto do_end_trans;
2090ff8f33c8SSteven Whitehouse 	}
2091a13b8c5fSWendy Cheng 
2092a13b8c5fSWendy Cheng 	error = gfs2_meta_inode_buffer(ip, &dibh);
2093a13b8c5fSWendy Cheng 	if (error)
2094ff8f33c8SSteven Whitehouse 		goto do_end_trans;
2095a13b8c5fSWendy Cheng 
2096b473bc2dSAndreas Gruenbacher 	truncate_setsize(inode, size);
20978a8b8d91SJeff Layton 	ip->i_inode.i_mtime = inode_set_ctime_current(&ip->i_inode);
2098350a9b0aSSteven Whitehouse 	gfs2_trans_add_meta(ip->i_gl, dibh);
2099a13b8c5fSWendy Cheng 	gfs2_dinode_out(ip, dibh->b_data);
2100a13b8c5fSWendy Cheng 	brelse(dibh);
2101a13b8c5fSWendy Cheng 
2102ff8f33c8SSteven Whitehouse do_end_trans:
2103a13b8c5fSWendy Cheng 	gfs2_trans_end(sdp);
2104ff8f33c8SSteven Whitehouse do_grow_release:
21052f7ee358SBob Peterson 	if (unstuff) {
2106ff8f33c8SSteven Whitehouse 		gfs2_inplace_release(ip);
2107ff8f33c8SSteven Whitehouse do_grow_qunlock:
2108ff8f33c8SSteven Whitehouse 		gfs2_quota_unlock(ip);
2109ff8f33c8SSteven Whitehouse 	}
2110a13b8c5fSWendy Cheng 	return error;
2111a13b8c5fSWendy Cheng }
2112a13b8c5fSWendy Cheng 
2113b3b94faaSDavid Teigland /**
2114ff8f33c8SSteven Whitehouse  * gfs2_setattr_size - make a file a given size
2115ff8f33c8SSteven Whitehouse  * @inode: the inode
2116ff8f33c8SSteven Whitehouse  * @newsize: the size to make the file
2117b3b94faaSDavid Teigland  *
2118ff8f33c8SSteven Whitehouse  * The file size can grow, shrink, or stay the same size. This
21193e7aafc3SBob Peterson  * is called holding i_rwsem and an exclusive glock on the inode
2120ff8f33c8SSteven Whitehouse  * in question.
2121b3b94faaSDavid Teigland  *
2122b3b94faaSDavid Teigland  * Returns: errno
2123b3b94faaSDavid Teigland  */
2124b3b94faaSDavid Teigland 
gfs2_setattr_size(struct inode * inode,u64 newsize)2125ff8f33c8SSteven Whitehouse int gfs2_setattr_size(struct inode *inode, u64 newsize)
2126b3b94faaSDavid Teigland {
2127af5c2697SSteven Whitehouse 	struct gfs2_inode *ip = GFS2_I(inode);
2128ff8f33c8SSteven Whitehouse 	int ret;
2129b3b94faaSDavid Teigland 
2130ff8f33c8SSteven Whitehouse 	BUG_ON(!S_ISREG(inode->i_mode));
2131b3b94faaSDavid Teigland 
2132ff8f33c8SSteven Whitehouse 	ret = inode_newsize_ok(inode, newsize);
2133ff8f33c8SSteven Whitehouse 	if (ret)
2134ff8f33c8SSteven Whitehouse 		return ret;
2135b3b94faaSDavid Teigland 
2136562c72aaSChristoph Hellwig 	inode_dio_wait(inode);
2137562c72aaSChristoph Hellwig 
21382fba46a0SBob Peterson 	ret = gfs2_qa_get(ip);
2139d2b47cfbSBob Peterson 	if (ret)
21402b3dcf35SBob Peterson 		goto out;
2141d2b47cfbSBob Peterson 
21428b5860a3SAndreas Gruenbacher 	if (newsize >= inode->i_size) {
21432b3dcf35SBob Peterson 		ret = do_grow(inode, newsize);
21442b3dcf35SBob Peterson 		goto out;
21452b3dcf35SBob Peterson 	}
2146ff8f33c8SSteven Whitehouse 
21478b5860a3SAndreas Gruenbacher 	ret = do_shrink(inode, newsize);
21482b3dcf35SBob Peterson out:
21497336905aSAndreas Gruenbacher 	gfs2_rs_delete(ip);
21501595548fSAndreas Gruenbacher 	gfs2_qa_put(ip);
21512b3dcf35SBob Peterson 	return ret;
2152b3b94faaSDavid Teigland }
2153b3b94faaSDavid Teigland 
gfs2_truncatei_resume(struct gfs2_inode * ip)2154b3b94faaSDavid Teigland int gfs2_truncatei_resume(struct gfs2_inode *ip)
2155b3b94faaSDavid Teigland {
2156b3b94faaSDavid Teigland 	int error;
215710d2cf94SAndreas Gruenbacher 	error = punch_hole(ip, i_size_read(&ip->i_inode), 0);
2158b3b94faaSDavid Teigland 	if (!error)
2159b3b94faaSDavid Teigland 		error = trunc_end(ip);
2160b3b94faaSDavid Teigland 	return error;
2161b3b94faaSDavid Teigland }
2162b3b94faaSDavid Teigland 
gfs2_file_dealloc(struct gfs2_inode * ip)2163b3b94faaSDavid Teigland int gfs2_file_dealloc(struct gfs2_inode *ip)
2164b3b94faaSDavid Teigland {
216510d2cf94SAndreas Gruenbacher 	return punch_hole(ip, 0, 0);
2166b3b94faaSDavid Teigland }
2167b3b94faaSDavid Teigland 
2168b3b94faaSDavid Teigland /**
2169b50f227bSSteven Whitehouse  * gfs2_free_journal_extents - Free cached journal bmap info
2170b50f227bSSteven Whitehouse  * @jd: The journal
2171b50f227bSSteven Whitehouse  *
2172b50f227bSSteven Whitehouse  */
2173b50f227bSSteven Whitehouse 
gfs2_free_journal_extents(struct gfs2_jdesc * jd)2174b50f227bSSteven Whitehouse void gfs2_free_journal_extents(struct gfs2_jdesc *jd)
2175b50f227bSSteven Whitehouse {
2176b50f227bSSteven Whitehouse 	struct gfs2_journal_extent *jext;
2177b50f227bSSteven Whitehouse 
2178b50f227bSSteven Whitehouse 	while(!list_empty(&jd->extent_list)) {
2179969183bcSAndreas Gruenbacher 		jext = list_first_entry(&jd->extent_list, struct gfs2_journal_extent, list);
2180b50f227bSSteven Whitehouse 		list_del(&jext->list);
2181b50f227bSSteven Whitehouse 		kfree(jext);
2182b50f227bSSteven Whitehouse 	}
2183b50f227bSSteven Whitehouse }
2184b50f227bSSteven Whitehouse 
2185b50f227bSSteven Whitehouse /**
2186b50f227bSSteven Whitehouse  * gfs2_add_jextent - Add or merge a new extent to extent cache
2187b50f227bSSteven Whitehouse  * @jd: The journal descriptor
2188b50f227bSSteven Whitehouse  * @lblock: The logical block at start of new extent
2189c62baf65SFabian Frederick  * @dblock: The physical block at start of new extent
2190b50f227bSSteven Whitehouse  * @blocks: Size of extent in fs blocks
2191b50f227bSSteven Whitehouse  *
2192b50f227bSSteven Whitehouse  * Returns: 0 on success or -ENOMEM
2193b50f227bSSteven Whitehouse  */
2194b50f227bSSteven Whitehouse 
gfs2_add_jextent(struct gfs2_jdesc * jd,u64 lblock,u64 dblock,u64 blocks)2195b50f227bSSteven Whitehouse static int gfs2_add_jextent(struct gfs2_jdesc *jd, u64 lblock, u64 dblock, u64 blocks)
2196b50f227bSSteven Whitehouse {
2197b50f227bSSteven Whitehouse 	struct gfs2_journal_extent *jext;
2198b50f227bSSteven Whitehouse 
2199b50f227bSSteven Whitehouse 	if (!list_empty(&jd->extent_list)) {
2200969183bcSAndreas Gruenbacher 		jext = list_last_entry(&jd->extent_list, struct gfs2_journal_extent, list);
2201b50f227bSSteven Whitehouse 		if ((jext->dblock + jext->blocks) == dblock) {
2202b50f227bSSteven Whitehouse 			jext->blocks += blocks;
2203b50f227bSSteven Whitehouse 			return 0;
2204b50f227bSSteven Whitehouse 		}
2205b50f227bSSteven Whitehouse 	}
2206b50f227bSSteven Whitehouse 
2207b50f227bSSteven Whitehouse 	jext = kzalloc(sizeof(struct gfs2_journal_extent), GFP_NOFS);
2208b50f227bSSteven Whitehouse 	if (jext == NULL)
2209b50f227bSSteven Whitehouse 		return -ENOMEM;
2210b50f227bSSteven Whitehouse 	jext->dblock = dblock;
2211b50f227bSSteven Whitehouse 	jext->lblock = lblock;
2212b50f227bSSteven Whitehouse 	jext->blocks = blocks;
2213b50f227bSSteven Whitehouse 	list_add_tail(&jext->list, &jd->extent_list);
2214b50f227bSSteven Whitehouse 	jd->nr_extents++;
2215b50f227bSSteven Whitehouse 	return 0;
2216b50f227bSSteven Whitehouse }
2217b50f227bSSteven Whitehouse 
2218b50f227bSSteven Whitehouse /**
2219b50f227bSSteven Whitehouse  * gfs2_map_journal_extents - Cache journal bmap info
2220b50f227bSSteven Whitehouse  * @sdp: The super block
2221b50f227bSSteven Whitehouse  * @jd: The journal to map
2222b50f227bSSteven Whitehouse  *
2223b50f227bSSteven Whitehouse  * Create a reusable "extent" mapping from all logical
2224b50f227bSSteven Whitehouse  * blocks to all physical blocks for the given journal.  This will save
2225b50f227bSSteven Whitehouse  * us time when writing journal blocks.  Most journals will have only one
2226b50f227bSSteven Whitehouse  * extent that maps all their logical blocks.  That's because gfs2.mkfs
2227b50f227bSSteven Whitehouse  * arranges the journal blocks sequentially to maximize performance.
2228b50f227bSSteven Whitehouse  * So the extent would map the first block for the entire file length.
2229b50f227bSSteven Whitehouse  * However, gfs2_jadd can happen while file activity is happening, so
2230b50f227bSSteven Whitehouse  * those journals may not be sequential.  Less likely is the case where
2231b50f227bSSteven Whitehouse  * the users created their own journals by mounting the metafs and
2232b50f227bSSteven Whitehouse  * laying it out.  But it's still possible.  These journals might have
2233b50f227bSSteven Whitehouse  * several extents.
2234b50f227bSSteven Whitehouse  *
2235b50f227bSSteven Whitehouse  * Returns: 0 on success, or error on failure
2236b50f227bSSteven Whitehouse  */
2237b50f227bSSteven Whitehouse 
gfs2_map_journal_extents(struct gfs2_sbd * sdp,struct gfs2_jdesc * jd)2238b50f227bSSteven Whitehouse int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd)
2239b50f227bSSteven Whitehouse {
2240b50f227bSSteven Whitehouse 	u64 lblock = 0;
2241b50f227bSSteven Whitehouse 	u64 lblock_stop;
2242b50f227bSSteven Whitehouse 	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
2243b50f227bSSteven Whitehouse 	struct buffer_head bh;
2244b50f227bSSteven Whitehouse 	unsigned int shift = sdp->sd_sb.sb_bsize_shift;
2245b50f227bSSteven Whitehouse 	u64 size;
2246b50f227bSSteven Whitehouse 	int rc;
224798583b3eSAbhi Das 	ktime_t start, end;
2248b50f227bSSteven Whitehouse 
224998583b3eSAbhi Das 	start = ktime_get();
2250b50f227bSSteven Whitehouse 	lblock_stop = i_size_read(jd->jd_inode) >> shift;
2251b50f227bSSteven Whitehouse 	size = (lblock_stop - lblock) << shift;
2252b50f227bSSteven Whitehouse 	jd->nr_extents = 0;
2253b50f227bSSteven Whitehouse 	WARN_ON(!list_empty(&jd->extent_list));
2254b50f227bSSteven Whitehouse 
2255b50f227bSSteven Whitehouse 	do {
2256b50f227bSSteven Whitehouse 		bh.b_state = 0;
2257b50f227bSSteven Whitehouse 		bh.b_blocknr = 0;
2258b50f227bSSteven Whitehouse 		bh.b_size = size;
2259b50f227bSSteven Whitehouse 		rc = gfs2_block_map(jd->jd_inode, lblock, &bh, 0);
2260b50f227bSSteven Whitehouse 		if (rc || !buffer_mapped(&bh))
2261b50f227bSSteven Whitehouse 			goto fail;
2262b50f227bSSteven Whitehouse 		rc = gfs2_add_jextent(jd, lblock, bh.b_blocknr, bh.b_size >> shift);
2263b50f227bSSteven Whitehouse 		if (rc)
2264b50f227bSSteven Whitehouse 			goto fail;
2265b50f227bSSteven Whitehouse 		size -= bh.b_size;
2266b50f227bSSteven Whitehouse 		lblock += (bh.b_size >> ip->i_inode.i_blkbits);
2267b50f227bSSteven Whitehouse 	} while(size > 0);
2268b50f227bSSteven Whitehouse 
226998583b3eSAbhi Das 	end = ktime_get();
227098583b3eSAbhi Das 	fs_info(sdp, "journal %d mapped with %u extents in %lldms\n", jd->jd_jid,
227198583b3eSAbhi Das 		jd->nr_extents, ktime_ms_delta(end, start));
2272b50f227bSSteven Whitehouse 	return 0;
2273b50f227bSSteven Whitehouse 
2274b50f227bSSteven Whitehouse fail:
2275b50f227bSSteven Whitehouse 	fs_warn(sdp, "error %d mapping journal %u at offset %llu (extent %u)\n",
2276b50f227bSSteven Whitehouse 		rc, jd->jd_jid,
2277b50f227bSSteven Whitehouse 		(unsigned long long)(i_size_read(jd->jd_inode) - size),
2278b50f227bSSteven Whitehouse 		jd->nr_extents);
2279b50f227bSSteven Whitehouse 	fs_warn(sdp, "bmap=%d lblock=%llu block=%llu, state=0x%08lx, size=%llu\n",
2280b50f227bSSteven Whitehouse 		rc, (unsigned long long)lblock, (unsigned long long)bh.b_blocknr,
2281b50f227bSSteven Whitehouse 		bh.b_state, (unsigned long long)bh.b_size);
2282b50f227bSSteven Whitehouse 	gfs2_free_journal_extents(jd);
2283b50f227bSSteven Whitehouse 	return rc;
2284b50f227bSSteven Whitehouse }
2285b50f227bSSteven Whitehouse 
2286b50f227bSSteven Whitehouse /**
2287b3b94faaSDavid Teigland  * gfs2_write_alloc_required - figure out if a write will require an allocation
2288b3b94faaSDavid Teigland  * @ip: the file being written to
2289b3b94faaSDavid Teigland  * @offset: the offset to write to
2290b3b94faaSDavid Teigland  * @len: the number of bytes being written
2291b3b94faaSDavid Teigland  *
2292461cb419SBob Peterson  * Returns: 1 if an alloc is required, 0 otherwise
2293b3b94faaSDavid Teigland  */
2294b3b94faaSDavid Teigland 
gfs2_write_alloc_required(struct gfs2_inode * ip,u64 offset,unsigned int len)2295cd915493SSteven Whitehouse int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
2296461cb419SBob Peterson 			      unsigned int len)
2297b3b94faaSDavid Teigland {
2298feaa7bbaSSteven Whitehouse 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
2299941e6d7dSSteven Whitehouse 	struct buffer_head bh;
2300941e6d7dSSteven Whitehouse 	unsigned int shift;
2301941e6d7dSSteven Whitehouse 	u64 lblock, lblock_stop, size;
23027ed122e4SSteven Whitehouse 	u64 end_of_file;
2303b3b94faaSDavid Teigland 
2304b3b94faaSDavid Teigland 	if (!len)
2305b3b94faaSDavid Teigland 		return 0;
2306b3b94faaSDavid Teigland 
2307b3b94faaSDavid Teigland 	if (gfs2_is_stuffed(ip)) {
2308235628c5SAndreas Gruenbacher 		if (offset + len > gfs2_max_stuffed_size(ip))
2309461cb419SBob Peterson 			return 1;
2310b3b94faaSDavid Teigland 		return 0;
2311b3b94faaSDavid Teigland 	}
2312b3b94faaSDavid Teigland 
2313941e6d7dSSteven Whitehouse 	shift = sdp->sd_sb.sb_bsize_shift;
23147ed122e4SSteven Whitehouse 	BUG_ON(gfs2_is_dir(ip));
2315a2e0f799SSteven Whitehouse 	end_of_file = (i_size_read(&ip->i_inode) + sdp->sd_sb.sb_bsize - 1) >> shift;
2316b3b94faaSDavid Teigland 	lblock = offset >> shift;
2317b3b94faaSDavid Teigland 	lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
231877612578SAndreas Gruenbacher 	if (lblock_stop > end_of_file && ip != GFS2_I(sdp->sd_rindex))
2319461cb419SBob Peterson 		return 1;
2320b3b94faaSDavid Teigland 
2321941e6d7dSSteven Whitehouse 	size = (lblock_stop - lblock) << shift;
2322941e6d7dSSteven Whitehouse 	do {
2323941e6d7dSSteven Whitehouse 		bh.b_state = 0;
2324941e6d7dSSteven Whitehouse 		bh.b_size = size;
2325941e6d7dSSteven Whitehouse 		gfs2_block_map(&ip->i_inode, lblock, &bh, 0);
2326941e6d7dSSteven Whitehouse 		if (!buffer_mapped(&bh))
2327461cb419SBob Peterson 			return 1;
2328941e6d7dSSteven Whitehouse 		size -= bh.b_size;
2329941e6d7dSSteven Whitehouse 		lblock += (bh.b_size >> ip->i_inode.i_blkbits);
2330941e6d7dSSteven Whitehouse 	} while(size > 0);
2331b3b94faaSDavid Teigland 
2332b3b94faaSDavid Teigland 	return 0;
2333b3b94faaSDavid Teigland }
2334b3b94faaSDavid Teigland 
stuffed_zero_range(struct inode * inode,loff_t offset,loff_t length)23354e56a641SAndreas Gruenbacher static int stuffed_zero_range(struct inode *inode, loff_t offset, loff_t length)
23364e56a641SAndreas Gruenbacher {
23374e56a641SAndreas Gruenbacher 	struct gfs2_inode *ip = GFS2_I(inode);
23384e56a641SAndreas Gruenbacher 	struct buffer_head *dibh;
23394e56a641SAndreas Gruenbacher 	int error;
23404e56a641SAndreas Gruenbacher 
23414e56a641SAndreas Gruenbacher 	if (offset >= inode->i_size)
23424e56a641SAndreas Gruenbacher 		return 0;
23434e56a641SAndreas Gruenbacher 	if (offset + length > inode->i_size)
23444e56a641SAndreas Gruenbacher 		length = inode->i_size - offset;
23454e56a641SAndreas Gruenbacher 
23464e56a641SAndreas Gruenbacher 	error = gfs2_meta_inode_buffer(ip, &dibh);
23474e56a641SAndreas Gruenbacher 	if (error)
23484e56a641SAndreas Gruenbacher 		return error;
23494e56a641SAndreas Gruenbacher 	gfs2_trans_add_meta(ip->i_gl, dibh);
23504e56a641SAndreas Gruenbacher 	memset(dibh->b_data + sizeof(struct gfs2_dinode) + offset, 0,
23514e56a641SAndreas Gruenbacher 	       length);
23524e56a641SAndreas Gruenbacher 	brelse(dibh);
23534e56a641SAndreas Gruenbacher 	return 0;
23544e56a641SAndreas Gruenbacher }
23554e56a641SAndreas Gruenbacher 
gfs2_journaled_truncate_range(struct inode * inode,loff_t offset,loff_t length)23564e56a641SAndreas Gruenbacher static int gfs2_journaled_truncate_range(struct inode *inode, loff_t offset,
23574e56a641SAndreas Gruenbacher 					 loff_t length)
23584e56a641SAndreas Gruenbacher {
23594e56a641SAndreas Gruenbacher 	struct gfs2_sbd *sdp = GFS2_SB(inode);
23604e56a641SAndreas Gruenbacher 	loff_t max_chunk = GFS2_JTRUNC_REVOKES * sdp->sd_vfs->s_blocksize;
23614e56a641SAndreas Gruenbacher 	int error;
23624e56a641SAndreas Gruenbacher 
23634e56a641SAndreas Gruenbacher 	while (length) {
23644e56a641SAndreas Gruenbacher 		struct gfs2_trans *tr;
23654e56a641SAndreas Gruenbacher 		loff_t chunk;
23664e56a641SAndreas Gruenbacher 		unsigned int offs;
23674e56a641SAndreas Gruenbacher 
23684e56a641SAndreas Gruenbacher 		chunk = length;
23694e56a641SAndreas Gruenbacher 		if (chunk > max_chunk)
23704e56a641SAndreas Gruenbacher 			chunk = max_chunk;
23714e56a641SAndreas Gruenbacher 
23724e56a641SAndreas Gruenbacher 		offs = offset & ~PAGE_MASK;
23734e56a641SAndreas Gruenbacher 		if (offs && chunk > PAGE_SIZE)
23744e56a641SAndreas Gruenbacher 			chunk = offs + ((chunk - offs) & PAGE_MASK);
23754e56a641SAndreas Gruenbacher 
23764e56a641SAndreas Gruenbacher 		truncate_pagecache_range(inode, offset, chunk);
23774e56a641SAndreas Gruenbacher 		offset += chunk;
23784e56a641SAndreas Gruenbacher 		length -= chunk;
23794e56a641SAndreas Gruenbacher 
23804e56a641SAndreas Gruenbacher 		tr = current->journal_info;
23814e56a641SAndreas Gruenbacher 		if (!test_bit(TR_TOUCHED, &tr->tr_flags))
23824e56a641SAndreas Gruenbacher 			continue;
23834e56a641SAndreas Gruenbacher 
23844e56a641SAndreas Gruenbacher 		gfs2_trans_end(sdp);
23854e56a641SAndreas Gruenbacher 		error = gfs2_trans_begin(sdp, RES_DINODE, GFS2_JTRUNC_REVOKES);
23864e56a641SAndreas Gruenbacher 		if (error)
23874e56a641SAndreas Gruenbacher 			return error;
23884e56a641SAndreas Gruenbacher 	}
23894e56a641SAndreas Gruenbacher 	return 0;
23904e56a641SAndreas Gruenbacher }
23914e56a641SAndreas Gruenbacher 
__gfs2_punch_hole(struct file * file,loff_t offset,loff_t length)23924e56a641SAndreas Gruenbacher int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)
23934e56a641SAndreas Gruenbacher {
23944e56a641SAndreas Gruenbacher 	struct inode *inode = file_inode(file);
23954e56a641SAndreas Gruenbacher 	struct gfs2_inode *ip = GFS2_I(inode);
23964e56a641SAndreas Gruenbacher 	struct gfs2_sbd *sdp = GFS2_SB(inode);
239739c3a948SAndreas Gruenbacher 	unsigned int blocksize = i_blocksize(inode);
239839c3a948SAndreas Gruenbacher 	loff_t start, end;
23994e56a641SAndreas Gruenbacher 	int error;
24004e56a641SAndreas Gruenbacher 
240170499cdfSBob Peterson 	if (!gfs2_is_stuffed(ip)) {
240239c3a948SAndreas Gruenbacher 		unsigned int start_off, end_len;
24034e56a641SAndreas Gruenbacher 
24044e56a641SAndreas Gruenbacher 		start_off = offset & (blocksize - 1);
240500251a16SAndreas Gruenbacher 		end_len = (offset + length) & (blocksize - 1);
24064e56a641SAndreas Gruenbacher 		if (start_off) {
24074e56a641SAndreas Gruenbacher 			unsigned int len = length;
24084e56a641SAndreas Gruenbacher 			if (length > blocksize - start_off)
24094e56a641SAndreas Gruenbacher 				len = blocksize - start_off;
24104e56a641SAndreas Gruenbacher 			error = gfs2_block_zero_range(inode, offset, len);
24114e56a641SAndreas Gruenbacher 			if (error)
24124e56a641SAndreas Gruenbacher 				goto out;
24134e56a641SAndreas Gruenbacher 			if (start_off + length < blocksize)
241400251a16SAndreas Gruenbacher 				end_len = 0;
24154e56a641SAndreas Gruenbacher 		}
241600251a16SAndreas Gruenbacher 		if (end_len) {
24174e56a641SAndreas Gruenbacher 			error = gfs2_block_zero_range(inode,
241800251a16SAndreas Gruenbacher 				offset + length - end_len, end_len);
24194e56a641SAndreas Gruenbacher 			if (error)
24204e56a641SAndreas Gruenbacher 				goto out;
24214e56a641SAndreas Gruenbacher 		}
24224e56a641SAndreas Gruenbacher 	}
24234e56a641SAndreas Gruenbacher 
242470499cdfSBob Peterson 	start = round_down(offset, blocksize);
242570499cdfSBob Peterson 	end = round_up(offset + length, blocksize) - 1;
242670499cdfSBob Peterson 	error = filemap_write_and_wait_range(inode->i_mapping, start, end);
242770499cdfSBob Peterson 	if (error)
242870499cdfSBob Peterson 		return error;
242970499cdfSBob Peterson 
243070499cdfSBob Peterson 	if (gfs2_is_jdata(ip))
243170499cdfSBob Peterson 		error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA,
243270499cdfSBob Peterson 					 GFS2_JTRUNC_REVOKES);
243370499cdfSBob Peterson 	else
243470499cdfSBob Peterson 		error = gfs2_trans_begin(sdp, RES_DINODE, 0);
243570499cdfSBob Peterson 	if (error)
243670499cdfSBob Peterson 		return error;
243770499cdfSBob Peterson 
243870499cdfSBob Peterson 	if (gfs2_is_stuffed(ip)) {
243970499cdfSBob Peterson 		error = stuffed_zero_range(inode, offset, length);
244070499cdfSBob Peterson 		if (error)
244170499cdfSBob Peterson 			goto out;
244270499cdfSBob Peterson 	}
244370499cdfSBob Peterson 
24444e56a641SAndreas Gruenbacher 	if (gfs2_is_jdata(ip)) {
24454e56a641SAndreas Gruenbacher 		BUG_ON(!current->journal_info);
24464e56a641SAndreas Gruenbacher 		gfs2_journaled_truncate_range(inode, offset, length);
24474e56a641SAndreas Gruenbacher 	} else
24484e56a641SAndreas Gruenbacher 		truncate_pagecache_range(inode, offset, offset + length - 1);
24494e56a641SAndreas Gruenbacher 
24504e56a641SAndreas Gruenbacher 	file_update_time(file);
24514e56a641SAndreas Gruenbacher 	mark_inode_dirty(inode);
24524e56a641SAndreas Gruenbacher 
24534e56a641SAndreas Gruenbacher 	if (current->journal_info)
24544e56a641SAndreas Gruenbacher 		gfs2_trans_end(sdp);
24554e56a641SAndreas Gruenbacher 
24564e56a641SAndreas Gruenbacher 	if (!gfs2_is_stuffed(ip))
24574e56a641SAndreas Gruenbacher 		error = punch_hole(ip, offset, length);
24584e56a641SAndreas Gruenbacher 
24594e56a641SAndreas Gruenbacher out:
24604e56a641SAndreas Gruenbacher 	if (current->journal_info)
24614e56a641SAndreas Gruenbacher 		gfs2_trans_end(sdp);
24624e56a641SAndreas Gruenbacher 	return error;
24634e56a641SAndreas Gruenbacher }
24642164f9b9SChristoph Hellwig 
gfs2_map_blocks(struct iomap_writepage_ctx * wpc,struct inode * inode,loff_t offset)24652164f9b9SChristoph Hellwig static int gfs2_map_blocks(struct iomap_writepage_ctx *wpc, struct inode *inode,
24662164f9b9SChristoph Hellwig 		loff_t offset)
24672164f9b9SChristoph Hellwig {
24682164f9b9SChristoph Hellwig 	int ret;
24692164f9b9SChristoph Hellwig 
24702164f9b9SChristoph Hellwig 	if (WARN_ON_ONCE(gfs2_is_stuffed(GFS2_I(inode))))
24712164f9b9SChristoph Hellwig 		return -EIO;
24722164f9b9SChristoph Hellwig 
24732164f9b9SChristoph Hellwig 	if (offset >= wpc->iomap.offset &&
24742164f9b9SChristoph Hellwig 	    offset < wpc->iomap.offset + wpc->iomap.length)
24752164f9b9SChristoph Hellwig 		return 0;
24762164f9b9SChristoph Hellwig 
24772164f9b9SChristoph Hellwig 	memset(&wpc->iomap, 0, sizeof(wpc->iomap));
247854992257SAndreas Gruenbacher 	ret = gfs2_iomap_get(inode, offset, INT_MAX, &wpc->iomap);
24792164f9b9SChristoph Hellwig 	return ret;
24802164f9b9SChristoph Hellwig }
24812164f9b9SChristoph Hellwig 
24822164f9b9SChristoph Hellwig const struct iomap_writeback_ops gfs2_writeback_ops = {
24832164f9b9SChristoph Hellwig 	.map_blocks		= gfs2_map_blocks,
24842164f9b9SChristoph Hellwig };
2485