blob: 318613010106bd554ebfbfb2d9f9f5bfc8803f7a [file] [log] [blame]
Koji Sato36a580e2009-04-06 19:01:25 -07001/*
2 * direct.c - NILFS direct block pointer.
3 *
4 * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 * Written by Koji Sato <koji@osrg.net>.
21 */
22
23#include <linux/errno.h>
24#include "nilfs.h"
25#include "page.h"
26#include "direct.h"
27#include "alloc.h"
Ryusuke Konishic3a7abf2009-05-25 02:47:14 +090028#include "dat.h"
Koji Sato36a580e2009-04-06 19:01:25 -070029
Ryusuke Konishi10ff8852010-07-10 18:07:04 +090030static inline __le64 *nilfs_direct_dptrs(const struct nilfs_bmap *direct)
Koji Sato36a580e2009-04-06 19:01:25 -070031{
32 return (__le64 *)
Ryusuke Konishi10ff8852010-07-10 18:07:04 +090033 ((struct nilfs_direct_node *)direct->b_u.u_data + 1);
Koji Sato36a580e2009-04-06 19:01:25 -070034}
35
36static inline __u64
Ryusuke Konishi10ff8852010-07-10 18:07:04 +090037nilfs_direct_get_ptr(const struct nilfs_bmap *direct, __u64 key)
Koji Sato36a580e2009-04-06 19:01:25 -070038{
Ryusuke Konishi25b8d7d2010-07-10 16:50:41 +090039 return le64_to_cpu(*(nilfs_direct_dptrs(direct) + key));
Koji Sato36a580e2009-04-06 19:01:25 -070040}
41
Ryusuke Konishi10ff8852010-07-10 18:07:04 +090042static inline void nilfs_direct_set_ptr(struct nilfs_bmap *direct,
Koji Sato36a580e2009-04-06 19:01:25 -070043 __u64 key, __u64 ptr)
44{
Ryusuke Konishi25b8d7d2010-07-10 16:50:41 +090045 *(nilfs_direct_dptrs(direct) + key) = cpu_to_le64(ptr);
Koji Sato36a580e2009-04-06 19:01:25 -070046}
47
Ryusuke Konishi10ff8852010-07-10 18:07:04 +090048static int nilfs_direct_lookup(const struct nilfs_bmap *direct,
Koji Sato36a580e2009-04-06 19:01:25 -070049 __u64 key, int level, __u64 *ptrp)
50{
Koji Sato36a580e2009-04-06 19:01:25 -070051 __u64 ptr;
52
Jiro SEKIBA5ee58142009-12-06 15:43:56 +090053 if (key > NILFS_DIRECT_KEY_MAX || level != 1)
54 return -ENOENT;
55 ptr = nilfs_direct_get_ptr(direct, key);
56 if (ptr == NILFS_BMAP_INVALID_PTR)
Koji Sato36a580e2009-04-06 19:01:25 -070057 return -ENOENT;
58
59 if (ptrp != NULL)
60 *ptrp = ptr;
61 return 0;
62}
63
Ryusuke Konishi10ff8852010-07-10 18:07:04 +090064static int nilfs_direct_lookup_contig(const struct nilfs_bmap *direct,
Ryusuke Konishic3a7abf2009-05-25 02:47:14 +090065 __u64 key, __u64 *ptrp,
66 unsigned maxblocks)
67{
Ryusuke Konishic3a7abf2009-05-25 02:47:14 +090068 struct inode *dat = NULL;
69 __u64 ptr, ptr2;
70 sector_t blocknr;
71 int ret, cnt;
72
Jiro SEKIBA5ee58142009-12-06 15:43:56 +090073 if (key > NILFS_DIRECT_KEY_MAX)
74 return -ENOENT;
75 ptr = nilfs_direct_get_ptr(direct, key);
76 if (ptr == NILFS_BMAP_INVALID_PTR)
Ryusuke Konishic3a7abf2009-05-25 02:47:14 +090077 return -ENOENT;
78
Ryusuke Konishi10ff8852010-07-10 18:07:04 +090079 if (NILFS_BMAP_USE_VBN(direct)) {
80 dat = nilfs_bmap_get_dat(direct);
Ryusuke Konishic3a7abf2009-05-25 02:47:14 +090081 ret = nilfs_dat_translate(dat, ptr, &blocknr);
82 if (ret < 0)
83 return ret;
84 ptr = blocknr;
85 }
86
87 maxblocks = min_t(unsigned, maxblocks, NILFS_DIRECT_KEY_MAX - key + 1);
88 for (cnt = 1; cnt < maxblocks &&
89 (ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) !=
90 NILFS_BMAP_INVALID_PTR;
91 cnt++) {
92 if (dat) {
93 ret = nilfs_dat_translate(dat, ptr2, &blocknr);
94 if (ret < 0)
95 return ret;
96 ptr2 = blocknr;
97 }
98 if (ptr2 != ptr + cnt)
99 break;
100 }
101 *ptrp = ptr;
102 return cnt;
103}
104
Koji Sato36a580e2009-04-06 19:01:25 -0700105static __u64
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900106nilfs_direct_find_target_v(const struct nilfs_bmap *direct, __u64 key)
Koji Sato36a580e2009-04-06 19:01:25 -0700107{
108 __u64 ptr;
109
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900110 ptr = nilfs_bmap_find_target_seq(direct, key);
Koji Sato36a580e2009-04-06 19:01:25 -0700111 if (ptr != NILFS_BMAP_INVALID_PTR)
112 /* sequential access */
113 return ptr;
114 else
115 /* block group */
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900116 return nilfs_bmap_find_target_in_group(direct);
Koji Sato36a580e2009-04-06 19:01:25 -0700117}
118
Koji Sato36a580e2009-04-06 19:01:25 -0700119static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
120{
Koji Sato36a580e2009-04-06 19:01:25 -0700121 union nilfs_bmap_ptr_req req;
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900122 struct inode *dat = NULL;
123 struct buffer_head *bh;
Koji Sato36a580e2009-04-06 19:01:25 -0700124 int ret;
125
Koji Sato36a580e2009-04-06 19:01:25 -0700126 if (key > NILFS_DIRECT_KEY_MAX)
127 return -ENOENT;
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900128 if (nilfs_direct_get_ptr(bmap, key) != NILFS_BMAP_INVALID_PTR)
Koji Sato36a580e2009-04-06 19:01:25 -0700129 return -EEXIST;
130
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900131 if (NILFS_BMAP_USE_VBN(bmap)) {
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900132 req.bpr_ptr = nilfs_direct_find_target_v(bmap, key);
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900133 dat = nilfs_bmap_get_dat(bmap);
134 }
135 ret = nilfs_bmap_prepare_alloc_ptr(bmap, &req, dat);
136 if (!ret) {
137 /* ptr must be a pointer to a buffer head. */
138 bh = (struct buffer_head *)((unsigned long)ptr);
139 set_buffer_nilfs_volatile(bh);
Koji Sato36a580e2009-04-06 19:01:25 -0700140
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900141 nilfs_bmap_commit_alloc_ptr(bmap, &req, dat);
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900142 nilfs_direct_set_ptr(bmap, key, req.bpr_ptr);
Koji Sato36a580e2009-04-06 19:01:25 -0700143
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900144 if (!nilfs_bmap_dirty(bmap))
145 nilfs_bmap_set_dirty(bmap);
Koji Sato36a580e2009-04-06 19:01:25 -0700146
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900147 if (NILFS_BMAP_USE_VBN(bmap))
Ryusuke Konishidc935be2010-07-10 22:21:54 +0900148 nilfs_bmap_set_target_v(bmap, key, req.bpr_ptr);
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900149
150 nilfs_bmap_add_blocks(bmap, 1);
151 }
Ryusuke Konishid4b96152009-05-24 03:25:44 +0900152 return ret;
Koji Sato36a580e2009-04-06 19:01:25 -0700153}
154
Koji Sato36a580e2009-04-06 19:01:25 -0700155static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key)
156{
Koji Sato36a580e2009-04-06 19:01:25 -0700157 union nilfs_bmap_ptr_req req;
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900158 struct inode *dat;
Koji Sato36a580e2009-04-06 19:01:25 -0700159 int ret;
160
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900161 if (key > NILFS_DIRECT_KEY_MAX ||
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900162 nilfs_direct_get_ptr(bmap, key) == NILFS_BMAP_INVALID_PTR)
Koji Sato36a580e2009-04-06 19:01:25 -0700163 return -ENOENT;
164
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900165 dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL;
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900166 req.bpr_ptr = nilfs_direct_get_ptr(bmap, key);
Koji Sato36a580e2009-04-06 19:01:25 -0700167
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900168 ret = nilfs_bmap_prepare_end_ptr(bmap, &req, dat);
169 if (!ret) {
170 nilfs_bmap_commit_end_ptr(bmap, &req, dat);
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900171 nilfs_direct_set_ptr(bmap, key, NILFS_BMAP_INVALID_PTR);
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900172 nilfs_bmap_sub_blocks(bmap, 1);
173 }
174 return ret;
Koji Sato36a580e2009-04-06 19:01:25 -0700175}
176
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900177static int nilfs_direct_last_key(const struct nilfs_bmap *direct, __u64 *keyp)
Koji Sato36a580e2009-04-06 19:01:25 -0700178{
Koji Sato36a580e2009-04-06 19:01:25 -0700179 __u64 key, lastkey;
180
Koji Sato36a580e2009-04-06 19:01:25 -0700181 lastkey = NILFS_DIRECT_KEY_MAX + 1;
182 for (key = NILFS_DIRECT_KEY_MIN; key <= NILFS_DIRECT_KEY_MAX; key++)
183 if (nilfs_direct_get_ptr(direct, key) !=
184 NILFS_BMAP_INVALID_PTR)
185 lastkey = key;
186
187 if (lastkey == NILFS_DIRECT_KEY_MAX + 1)
188 return -ENOENT;
189
Koji Sato36a580e2009-04-06 19:01:25 -0700190 *keyp = lastkey;
191
192 return 0;
193}
194
195static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key)
196{
197 return key > NILFS_DIRECT_KEY_MAX;
198}
199
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900200static int nilfs_direct_gather_data(struct nilfs_bmap *direct,
Koji Sato36a580e2009-04-06 19:01:25 -0700201 __u64 *keys, __u64 *ptrs, int nitems)
202{
Koji Sato36a580e2009-04-06 19:01:25 -0700203 __u64 key;
204 __u64 ptr;
205 int n;
206
Koji Sato36a580e2009-04-06 19:01:25 -0700207 if (nitems > NILFS_DIRECT_NBLOCKS)
208 nitems = NILFS_DIRECT_NBLOCKS;
209 n = 0;
210 for (key = 0; key < nitems; key++) {
211 ptr = nilfs_direct_get_ptr(direct, key);
212 if (ptr != NILFS_BMAP_INVALID_PTR) {
213 keys[n] = key;
214 ptrs[n] = ptr;
215 n++;
216 }
217 }
218 return n;
219}
220
221int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
Ryusuke Konishi30333422009-05-24 00:09:44 +0900222 __u64 key, __u64 *keys, __u64 *ptrs, int n)
Koji Sato36a580e2009-04-06 19:01:25 -0700223{
Koji Sato36a580e2009-04-06 19:01:25 -0700224 __le64 *dptrs;
225 int ret, i, j;
226
227 /* no need to allocate any resource for conversion */
228
229 /* delete */
Pekka Enberg8acfbf02009-04-06 19:01:49 -0700230 ret = bmap->b_ops->bop_delete(bmap, key);
Koji Sato36a580e2009-04-06 19:01:25 -0700231 if (ret < 0)
232 return ret;
233
234 /* free resources */
235 if (bmap->b_ops->bop_clear != NULL)
Pekka Enberg8acfbf02009-04-06 19:01:49 -0700236 bmap->b_ops->bop_clear(bmap);
Koji Sato36a580e2009-04-06 19:01:25 -0700237
238 /* convert */
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900239 dptrs = nilfs_direct_dptrs(bmap);
Koji Sato36a580e2009-04-06 19:01:25 -0700240 for (i = 0, j = 0; i < NILFS_DIRECT_NBLOCKS; i++) {
241 if ((j < n) && (i == keys[j])) {
242 dptrs[i] = (i != key) ?
Ryusuke Konishi25b8d7d2010-07-10 16:50:41 +0900243 cpu_to_le64(ptrs[j]) :
Koji Sato36a580e2009-04-06 19:01:25 -0700244 NILFS_BMAP_INVALID_PTR;
245 j++;
246 } else
247 dptrs[i] = NILFS_BMAP_INVALID_PTR;
248 }
249
Ryusuke Konishi30333422009-05-24 00:09:44 +0900250 nilfs_direct_init(bmap);
Koji Sato36a580e2009-04-06 19:01:25 -0700251 return 0;
252}
253
Ryusuke Konishi583ada42010-07-10 21:37:47 +0900254static int nilfs_direct_propagate(struct nilfs_bmap *bmap,
Koji Sato36a580e2009-04-06 19:01:25 -0700255 struct buffer_head *bh)
256{
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900257 struct nilfs_palloc_req oldreq, newreq;
258 struct inode *dat;
259 __u64 key;
260 __u64 ptr;
261 int ret;
Koji Sato36a580e2009-04-06 19:01:25 -0700262
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900263 if (!NILFS_BMAP_USE_VBN(bmap))
264 return 0;
265
266 dat = nilfs_bmap_get_dat(bmap);
267 key = nilfs_bmap_data_get_key(bmap, bh);
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900268 ptr = nilfs_direct_get_ptr(bmap, key);
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900269 if (!buffer_nilfs_volatile(bh)) {
270 oldreq.pr_entry_nr = ptr;
271 newreq.pr_entry_nr = ptr;
272 ret = nilfs_dat_prepare_update(dat, &oldreq, &newreq);
273 if (ret < 0)
274 return ret;
275 nilfs_dat_commit_update(dat, &oldreq, &newreq,
276 bmap->b_ptr_type == NILFS_BMAP_PTR_VS);
277 set_buffer_nilfs_volatile(bh);
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900278 nilfs_direct_set_ptr(bmap, key, newreq.pr_entry_nr);
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900279 } else
280 ret = nilfs_dat_mark_dirty(dat, ptr);
281
282 return ret;
Koji Sato36a580e2009-04-06 19:01:25 -0700283}
284
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900285static int nilfs_direct_assign_v(struct nilfs_bmap *direct,
Koji Sato36a580e2009-04-06 19:01:25 -0700286 __u64 key, __u64 ptr,
287 struct buffer_head **bh,
288 sector_t blocknr,
289 union nilfs_binfo *binfo)
290{
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900291 struct inode *dat = nilfs_bmap_get_dat(direct);
Koji Sato36a580e2009-04-06 19:01:25 -0700292 union nilfs_bmap_ptr_req req;
293 int ret;
294
295 req.bpr_ptr = ptr;
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900296 ret = nilfs_dat_prepare_start(dat, &req.bpr_req);
297 if (!ret) {
298 nilfs_dat_commit_start(dat, &req.bpr_req, blocknr);
Ryusuke Konishi25b8d7d2010-07-10 16:50:41 +0900299 binfo->bi_v.bi_vblocknr = cpu_to_le64(ptr);
300 binfo->bi_v.bi_blkoff = cpu_to_le64(key);
Ryusuke Konishi2e0c2c72009-08-15 15:34:33 +0900301 }
302 return ret;
Koji Sato36a580e2009-04-06 19:01:25 -0700303}
304
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900305static int nilfs_direct_assign_p(struct nilfs_bmap *direct,
Koji Sato36a580e2009-04-06 19:01:25 -0700306 __u64 key, __u64 ptr,
307 struct buffer_head **bh,
308 sector_t blocknr,
309 union nilfs_binfo *binfo)
310{
311 nilfs_direct_set_ptr(direct, key, blocknr);
312
Ryusuke Konishi25b8d7d2010-07-10 16:50:41 +0900313 binfo->bi_dat.bi_blkoff = cpu_to_le64(key);
Koji Sato36a580e2009-04-06 19:01:25 -0700314 binfo->bi_dat.bi_level = 0;
315
316 return 0;
317}
318
319static int nilfs_direct_assign(struct nilfs_bmap *bmap,
320 struct buffer_head **bh,
321 sector_t blocknr,
322 union nilfs_binfo *binfo)
323{
Koji Sato36a580e2009-04-06 19:01:25 -0700324 __u64 key;
325 __u64 ptr;
326
Koji Sato36a580e2009-04-06 19:01:25 -0700327 key = nilfs_bmap_data_get_key(bmap, *bh);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700328 if (unlikely(key > NILFS_DIRECT_KEY_MAX)) {
329 printk(KERN_CRIT "%s: invalid key: %llu\n", __func__,
330 (unsigned long long)key);
331 return -EINVAL;
332 }
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900333 ptr = nilfs_direct_get_ptr(bmap, key);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700334 if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) {
335 printk(KERN_CRIT "%s: invalid pointer: %llu\n", __func__,
336 (unsigned long long)ptr);
337 return -EINVAL;
338 }
Koji Sato36a580e2009-04-06 19:01:25 -0700339
Ryusuke Konishi355c6b62009-05-24 16:46:37 +0900340 return NILFS_BMAP_USE_VBN(bmap) ?
Ryusuke Konishi10ff8852010-07-10 18:07:04 +0900341 nilfs_direct_assign_v(bmap, key, ptr, bh, blocknr, binfo) :
342 nilfs_direct_assign_p(bmap, key, ptr, bh, blocknr, binfo);
Koji Sato36a580e2009-04-06 19:01:25 -0700343}
344
345static const struct nilfs_bmap_operations nilfs_direct_ops = {
346 .bop_lookup = nilfs_direct_lookup,
Ryusuke Konishic3a7abf2009-05-25 02:47:14 +0900347 .bop_lookup_contig = nilfs_direct_lookup_contig,
Koji Sato36a580e2009-04-06 19:01:25 -0700348 .bop_insert = nilfs_direct_insert,
349 .bop_delete = nilfs_direct_delete,
350 .bop_clear = NULL,
351
352 .bop_propagate = nilfs_direct_propagate,
353
354 .bop_lookup_dirty_buffers = NULL,
355
356 .bop_assign = nilfs_direct_assign,
357 .bop_mark = NULL,
358
359 .bop_last_key = nilfs_direct_last_key,
360 .bop_check_insert = nilfs_direct_check_insert,
361 .bop_check_delete = NULL,
362 .bop_gather_data = nilfs_direct_gather_data,
363};
364
365
Ryusuke Konishi30333422009-05-24 00:09:44 +0900366int nilfs_direct_init(struct nilfs_bmap *bmap)
Koji Sato36a580e2009-04-06 19:01:25 -0700367{
Koji Sato36a580e2009-04-06 19:01:25 -0700368 bmap->b_ops = &nilfs_direct_ops;
Koji Sato36a580e2009-04-06 19:01:25 -0700369 return 0;
370}