xref: /freebsd/sys/fs/ext2fs/ext2_extents.c (revision d7511a40a749d2c42fa6f3fd74c7bdf37ad62a2c)
1*d7511a40SPedro F. Giffuni /*-
2*d7511a40SPedro F. Giffuni  * Copyright (c) 2010 Zheng Liu <lz@freebsd.org>
3*d7511a40SPedro F. Giffuni  * All rights reserved.
4*d7511a40SPedro F. Giffuni  *
5*d7511a40SPedro F. Giffuni  * Redistribution and use in source and binary forms, with or without
6*d7511a40SPedro F. Giffuni  * modification, are permitted provided that the following conditions
7*d7511a40SPedro F. Giffuni  * are met:
8*d7511a40SPedro F. Giffuni  * 1. Redistributions of source code must retain the above copyright
9*d7511a40SPedro F. Giffuni  *    notice, this list of conditions and the following disclaimer.
10*d7511a40SPedro F. Giffuni  * 2. Redistributions in binary form must reproduce the above copyright
11*d7511a40SPedro F. Giffuni  *    notice, this list of conditions and the following disclaimer in the
12*d7511a40SPedro F. Giffuni  *    documentation and/or other materials provided with the distribution.
13*d7511a40SPedro F. Giffuni  *
14*d7511a40SPedro F. Giffuni  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*d7511a40SPedro F. Giffuni  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*d7511a40SPedro F. Giffuni  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*d7511a40SPedro F. Giffuni  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*d7511a40SPedro F. Giffuni  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*d7511a40SPedro F. Giffuni  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*d7511a40SPedro F. Giffuni  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*d7511a40SPedro F. Giffuni  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*d7511a40SPedro F. Giffuni  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*d7511a40SPedro F. Giffuni  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*d7511a40SPedro F. Giffuni  * SUCH DAMAGE.
25*d7511a40SPedro F. Giffuni  *
26*d7511a40SPedro F. Giffuni  * $FreeBSD$
27*d7511a40SPedro F. Giffuni  */
28*d7511a40SPedro F. Giffuni 
29*d7511a40SPedro F. Giffuni #include <sys/param.h>
30*d7511a40SPedro F. Giffuni #include <sys/systm.h>
31*d7511a40SPedro F. Giffuni #include <sys/types.h>
32*d7511a40SPedro F. Giffuni #include <sys/kernel.h>
33*d7511a40SPedro F. Giffuni #include <sys/malloc.h>
34*d7511a40SPedro F. Giffuni #include <sys/vnode.h>
35*d7511a40SPedro F. Giffuni #include <sys/bio.h>
36*d7511a40SPedro F. Giffuni #include <sys/buf.h>
37*d7511a40SPedro F. Giffuni #include <sys/conf.h>
38*d7511a40SPedro F. Giffuni 
39*d7511a40SPedro F. Giffuni #include <fs/ext2fs/ext2_mount.h>
40*d7511a40SPedro F. Giffuni #include <fs/ext2fs/fs.h>
41*d7511a40SPedro F. Giffuni #include <fs/ext2fs/inode.h>
42*d7511a40SPedro F. Giffuni #include <fs/ext2fs/ext2fs.h>
43*d7511a40SPedro F. Giffuni #include <fs/ext2fs/ext2_extents.h>
44*d7511a40SPedro F. Giffuni #include <fs/ext2fs/ext2_extern.h>
45*d7511a40SPedro F. Giffuni 
46*d7511a40SPedro F. Giffuni static void ext4_ext_binsearch_index(struct inode *ip, struct ext4_extent_path
47*d7511a40SPedro F. Giffuni 		*path, daddr_t lbn)
48*d7511a40SPedro F. Giffuni {
49*d7511a40SPedro F. Giffuni 	struct ext4_extent_header *ehp = path->ep_header;
50*d7511a40SPedro F. Giffuni 	struct ext4_extent_index *l, *r, *m;
51*d7511a40SPedro F. Giffuni 
52*d7511a40SPedro F. Giffuni 	l = (struct ext4_extent_index *)(char *)(ehp + 1);
53*d7511a40SPedro F. Giffuni 	r = (struct ext4_extent_index *)(char *)(ehp + 1) + ehp->eh_ecount - 1;
54*d7511a40SPedro F. Giffuni 	while (l <= r) {
55*d7511a40SPedro F. Giffuni 		m = l + (r - l) / 2;
56*d7511a40SPedro F. Giffuni 		if (lbn < m->ei_blk)
57*d7511a40SPedro F. Giffuni 			r = m - 1;
58*d7511a40SPedro F. Giffuni 		else
59*d7511a40SPedro F. Giffuni 			l = m + 1;
60*d7511a40SPedro F. Giffuni 	}
61*d7511a40SPedro F. Giffuni 
62*d7511a40SPedro F. Giffuni 	path->ep_index = l - 1;
63*d7511a40SPedro F. Giffuni }
64*d7511a40SPedro F. Giffuni 
65*d7511a40SPedro F. Giffuni static void
66*d7511a40SPedro F. Giffuni ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn)
67*d7511a40SPedro F. Giffuni {
68*d7511a40SPedro F. Giffuni 	struct ext4_extent_header *ehp = path->ep_header;
69*d7511a40SPedro F. Giffuni 	struct ext4_extent *l, *r, *m;
70*d7511a40SPedro F. Giffuni 
71*d7511a40SPedro F. Giffuni 	if (ehp->eh_ecount == 0)
72*d7511a40SPedro F. Giffuni 		return;
73*d7511a40SPedro F. Giffuni 
74*d7511a40SPedro F. Giffuni 	l = (struct ext4_extent *)(char *)(ehp + 1);
75*d7511a40SPedro F. Giffuni 	r = (struct ext4_extent *)(char *)(ehp + 1) + ehp->eh_ecount - 1;
76*d7511a40SPedro F. Giffuni 	while (l <= r) {
77*d7511a40SPedro F. Giffuni 		m = l + (r - l) / 2;
78*d7511a40SPedro F. Giffuni 		if (lbn < m->e_blk)
79*d7511a40SPedro F. Giffuni 			r = m - 1;
80*d7511a40SPedro F. Giffuni 		else
81*d7511a40SPedro F. Giffuni 			l = m + 1;
82*d7511a40SPedro F. Giffuni 	}
83*d7511a40SPedro F. Giffuni 
84*d7511a40SPedro F. Giffuni 	path->ep_ext = l - 1;
85*d7511a40SPedro F. Giffuni }
86*d7511a40SPedro F. Giffuni 
87*d7511a40SPedro F. Giffuni /*
88*d7511a40SPedro F. Giffuni  * Find a block in ext4 extent cache.
89*d7511a40SPedro F. Giffuni  */
90*d7511a40SPedro F. Giffuni int
91*d7511a40SPedro F. Giffuni ext4_ext_in_cache(struct inode *ip, daddr_t lbn, struct ext4_extent *ep)
92*d7511a40SPedro F. Giffuni {
93*d7511a40SPedro F. Giffuni 	struct ext4_extent_cache *ecp;
94*d7511a40SPedro F. Giffuni 	int ret = EXT4_EXT_CACHE_NO;
95*d7511a40SPedro F. Giffuni 
96*d7511a40SPedro F. Giffuni 	ecp = &ip->i_ext_cache;
97*d7511a40SPedro F. Giffuni 
98*d7511a40SPedro F. Giffuni 	/* cache is invalid */
99*d7511a40SPedro F. Giffuni 	if (ecp->ec_type == EXT4_EXT_CACHE_NO)
100*d7511a40SPedro F. Giffuni 		return (ret);
101*d7511a40SPedro F. Giffuni 
102*d7511a40SPedro F. Giffuni 	if (lbn >= ecp->ec_blk && lbn < ecp->ec_blk + ecp->ec_len) {
103*d7511a40SPedro F. Giffuni 		ep->e_blk = ecp->ec_blk;
104*d7511a40SPedro F. Giffuni 		ep->e_start_lo = ecp->ec_start & 0xffffffff;
105*d7511a40SPedro F. Giffuni 		ep->e_start_hi = ecp->ec_start >> 32 & 0xffff;
106*d7511a40SPedro F. Giffuni 		ep->e_len = ecp->ec_len;
107*d7511a40SPedro F. Giffuni 		ret = ecp->ec_type;
108*d7511a40SPedro F. Giffuni 	}
109*d7511a40SPedro F. Giffuni 	return (ret);
110*d7511a40SPedro F. Giffuni }
111*d7511a40SPedro F. Giffuni 
112*d7511a40SPedro F. Giffuni /*
113*d7511a40SPedro F. Giffuni  * Put an ext4_extent structure in ext4 cache.
114*d7511a40SPedro F. Giffuni  */
115*d7511a40SPedro F. Giffuni void
116*d7511a40SPedro F. Giffuni ext4_ext_put_cache(struct inode *ip, struct ext4_extent *ep, int type)
117*d7511a40SPedro F. Giffuni {
118*d7511a40SPedro F. Giffuni 	struct ext4_extent_cache *ecp;
119*d7511a40SPedro F. Giffuni 
120*d7511a40SPedro F. Giffuni 	ecp = &ip->i_ext_cache;
121*d7511a40SPedro F. Giffuni 	ecp->ec_type = type;
122*d7511a40SPedro F. Giffuni 	ecp->ec_blk = ep->e_blk;
123*d7511a40SPedro F. Giffuni 	ecp->ec_len = ep->e_len;
124*d7511a40SPedro F. Giffuni 	ecp->ec_start = (daddr_t)ep->e_start_hi << 32 | ep->e_start_lo;
125*d7511a40SPedro F. Giffuni }
126*d7511a40SPedro F. Giffuni 
127*d7511a40SPedro F. Giffuni /*
128*d7511a40SPedro F. Giffuni  * Find an extent.
129*d7511a40SPedro F. Giffuni  */
130*d7511a40SPedro F. Giffuni struct ext4_extent_path *
131*d7511a40SPedro F. Giffuni ext4_ext_find_extent(struct m_ext2fs *fs, struct inode *ip,
132*d7511a40SPedro F. Giffuni 		     daddr_t lbn, struct ext4_extent_path *path)
133*d7511a40SPedro F. Giffuni {
134*d7511a40SPedro F. Giffuni 	struct vnode *vp;
135*d7511a40SPedro F. Giffuni 	struct ext4_extent_header *ehp;
136*d7511a40SPedro F. Giffuni 	uint16_t i;
137*d7511a40SPedro F. Giffuni 	int error, size;
138*d7511a40SPedro F. Giffuni 	daddr_t nblk;
139*d7511a40SPedro F. Giffuni 
140*d7511a40SPedro F. Giffuni 	vp = ITOV(ip);
141*d7511a40SPedro F. Giffuni 	ehp = (struct ext4_extent_header *)(char *)ip->i_db;
142*d7511a40SPedro F. Giffuni 
143*d7511a40SPedro F. Giffuni 	if (ehp->eh_magic != EXT4_EXT_MAGIC)
144*d7511a40SPedro F. Giffuni 		return (NULL);
145*d7511a40SPedro F. Giffuni 
146*d7511a40SPedro F. Giffuni 	path->ep_header = ehp;
147*d7511a40SPedro F. Giffuni 
148*d7511a40SPedro F. Giffuni 	for (i = ehp->eh_depth; i != 0; --i) {
149*d7511a40SPedro F. Giffuni 		ext4_ext_binsearch_index(ip, path, lbn);
150*d7511a40SPedro F. Giffuni 		path->ep_depth = 0;
151*d7511a40SPedro F. Giffuni 		path->ep_ext = NULL;
152*d7511a40SPedro F. Giffuni 
153*d7511a40SPedro F. Giffuni 		nblk = (daddr_t)path->ep_index->ei_leaf_hi << 32 |
154*d7511a40SPedro F. Giffuni 		    path->ep_index->ei_leaf_lo;
155*d7511a40SPedro F. Giffuni 		size = blksize(fs, ip, nblk);
156*d7511a40SPedro F. Giffuni 		if (path->ep_bp != NULL) {
157*d7511a40SPedro F. Giffuni 			brelse(path->ep_bp);
158*d7511a40SPedro F. Giffuni 			path->ep_bp = NULL;
159*d7511a40SPedro F. Giffuni 		}
160*d7511a40SPedro F. Giffuni 		error = bread(ip->i_devvp, fsbtodb(fs, nblk), size, NOCRED,
161*d7511a40SPedro F. Giffuni 			    &path->ep_bp);
162*d7511a40SPedro F. Giffuni 		if (error) {
163*d7511a40SPedro F. Giffuni 			brelse(path->ep_bp);
164*d7511a40SPedro F. Giffuni 			path->ep_bp = NULL;
165*d7511a40SPedro F. Giffuni 			return (NULL);
166*d7511a40SPedro F. Giffuni 		}
167*d7511a40SPedro F. Giffuni 		ehp = (struct ext4_extent_header *)path->ep_bp->b_data;
168*d7511a40SPedro F. Giffuni 		path->ep_header = ehp;
169*d7511a40SPedro F. Giffuni 	}
170*d7511a40SPedro F. Giffuni 
171*d7511a40SPedro F. Giffuni 	path->ep_depth = i;
172*d7511a40SPedro F. Giffuni 	path->ep_ext = NULL;
173*d7511a40SPedro F. Giffuni 	path->ep_index = NULL;
174*d7511a40SPedro F. Giffuni 
175*d7511a40SPedro F. Giffuni 	ext4_ext_binsearch(ip, path, lbn);
176*d7511a40SPedro F. Giffuni 	return (path);
177*d7511a40SPedro F. Giffuni }
178