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