1 /* 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" 28 29 static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct) 30 { 31 return (__le64 *) 32 ((struct nilfs_direct_node *)direct->d_bmap.b_u.u_data + 1); 33 } 34 35 static inline __u64 36 nilfs_direct_get_ptr(const struct nilfs_direct *direct, __u64 key) 37 { 38 return nilfs_bmap_dptr_to_ptr(*(nilfs_direct_dptrs(direct) + key)); 39 } 40 41 static inline void nilfs_direct_set_ptr(struct nilfs_direct *direct, 42 __u64 key, __u64 ptr) 43 { 44 *(nilfs_direct_dptrs(direct) + key) = nilfs_bmap_ptr_to_dptr(ptr); 45 } 46 47 static int nilfs_direct_lookup(const struct nilfs_bmap *bmap, 48 __u64 key, int level, __u64 *ptrp) 49 { 50 struct nilfs_direct *direct; 51 __u64 ptr; 52 53 direct = (struct nilfs_direct *)bmap; 54 if ((key > NILFS_DIRECT_KEY_MAX) || 55 (level != 1) || /* XXX: use macro for level 1 */ 56 ((ptr = nilfs_direct_get_ptr(direct, key)) == 57 NILFS_BMAP_INVALID_PTR)) 58 return -ENOENT; 59 60 if (ptrp != NULL) 61 *ptrp = ptr; 62 return 0; 63 } 64 65 static __u64 66 nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key) 67 { 68 __u64 ptr; 69 70 ptr = nilfs_bmap_find_target_seq(&direct->d_bmap, key); 71 if (ptr != NILFS_BMAP_INVALID_PTR) 72 /* sequential access */ 73 return ptr; 74 else 75 /* block group */ 76 return nilfs_bmap_find_target_in_group(&direct->d_bmap); 77 } 78 79 static void nilfs_direct_set_target_v(struct nilfs_direct *direct, 80 __u64 key, __u64 ptr) 81 { 82 direct->d_bmap.b_last_allocated_key = key; 83 direct->d_bmap.b_last_allocated_ptr = ptr; 84 } 85 86 static int nilfs_direct_prepare_insert(struct nilfs_direct *direct, 87 __u64 key, 88 union nilfs_bmap_ptr_req *req, 89 struct nilfs_bmap_stats *stats) 90 { 91 int ret; 92 93 if (direct->d_ops->dop_find_target != NULL) 94 req->bpr_ptr = direct->d_ops->dop_find_target(direct, key); 95 ret = direct->d_bmap.b_pops->bpop_prepare_alloc_ptr(&direct->d_bmap, 96 req); 97 if (ret < 0) 98 return ret; 99 100 stats->bs_nblocks = 1; 101 return 0; 102 } 103 104 static void nilfs_direct_commit_insert(struct nilfs_direct *direct, 105 union nilfs_bmap_ptr_req *req, 106 __u64 key, __u64 ptr) 107 { 108 struct buffer_head *bh; 109 110 /* ptr must be a pointer to a buffer head. */ 111 bh = (struct buffer_head *)((unsigned long)ptr); 112 set_buffer_nilfs_volatile(bh); 113 114 if (direct->d_bmap.b_pops->bpop_commit_alloc_ptr != NULL) 115 direct->d_bmap.b_pops->bpop_commit_alloc_ptr( 116 &direct->d_bmap, req); 117 nilfs_direct_set_ptr(direct, key, req->bpr_ptr); 118 119 if (!nilfs_bmap_dirty(&direct->d_bmap)) 120 nilfs_bmap_set_dirty(&direct->d_bmap); 121 122 if (direct->d_ops->dop_set_target != NULL) 123 direct->d_ops->dop_set_target(direct, key, req->bpr_ptr); 124 } 125 126 static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) 127 { 128 struct nilfs_direct *direct; 129 union nilfs_bmap_ptr_req req; 130 struct nilfs_bmap_stats stats; 131 int ret; 132 133 direct = (struct nilfs_direct *)bmap; 134 if (key > NILFS_DIRECT_KEY_MAX) 135 return -ENOENT; 136 if (nilfs_direct_get_ptr(direct, key) != NILFS_BMAP_INVALID_PTR) 137 return -EEXIST; 138 139 ret = nilfs_direct_prepare_insert(direct, key, &req, &stats); 140 if (ret < 0) 141 return ret; 142 nilfs_direct_commit_insert(direct, &req, key, ptr); 143 nilfs_bmap_add_blocks(bmap, stats.bs_nblocks); 144 145 return 0; 146 } 147 148 static int nilfs_direct_prepare_delete(struct nilfs_direct *direct, 149 union nilfs_bmap_ptr_req *req, 150 __u64 key, 151 struct nilfs_bmap_stats *stats) 152 { 153 int ret; 154 155 if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) { 156 req->bpr_ptr = nilfs_direct_get_ptr(direct, key); 157 ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr( 158 &direct->d_bmap, req); 159 if (ret < 0) 160 return ret; 161 } 162 163 stats->bs_nblocks = 1; 164 return 0; 165 } 166 167 static void nilfs_direct_commit_delete(struct nilfs_direct *direct, 168 union nilfs_bmap_ptr_req *req, 169 __u64 key) 170 { 171 if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL) 172 direct->d_bmap.b_pops->bpop_commit_end_ptr( 173 &direct->d_bmap, req); 174 nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); 175 } 176 177 static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key) 178 { 179 struct nilfs_direct *direct; 180 union nilfs_bmap_ptr_req req; 181 struct nilfs_bmap_stats stats; 182 int ret; 183 184 direct = (struct nilfs_direct *)bmap; 185 if ((key > NILFS_DIRECT_KEY_MAX) || 186 nilfs_direct_get_ptr(direct, key) == NILFS_BMAP_INVALID_PTR) 187 return -ENOENT; 188 189 ret = nilfs_direct_prepare_delete(direct, &req, key, &stats); 190 if (ret < 0) 191 return ret; 192 nilfs_direct_commit_delete(direct, &req, key); 193 nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks); 194 195 return 0; 196 } 197 198 static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp) 199 { 200 struct nilfs_direct *direct; 201 __u64 key, lastkey; 202 203 direct = (struct nilfs_direct *)bmap; 204 lastkey = NILFS_DIRECT_KEY_MAX + 1; 205 for (key = NILFS_DIRECT_KEY_MIN; key <= NILFS_DIRECT_KEY_MAX; key++) 206 if (nilfs_direct_get_ptr(direct, key) != 207 NILFS_BMAP_INVALID_PTR) 208 lastkey = key; 209 210 if (lastkey == NILFS_DIRECT_KEY_MAX + 1) 211 return -ENOENT; 212 213 *keyp = lastkey; 214 215 return 0; 216 } 217 218 static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key) 219 { 220 return key > NILFS_DIRECT_KEY_MAX; 221 } 222 223 static int nilfs_direct_gather_data(struct nilfs_bmap *bmap, 224 __u64 *keys, __u64 *ptrs, int nitems) 225 { 226 struct nilfs_direct *direct; 227 __u64 key; 228 __u64 ptr; 229 int n; 230 231 direct = (struct nilfs_direct *)bmap; 232 if (nitems > NILFS_DIRECT_NBLOCKS) 233 nitems = NILFS_DIRECT_NBLOCKS; 234 n = 0; 235 for (key = 0; key < nitems; key++) { 236 ptr = nilfs_direct_get_ptr(direct, key); 237 if (ptr != NILFS_BMAP_INVALID_PTR) { 238 keys[n] = key; 239 ptrs[n] = ptr; 240 n++; 241 } 242 } 243 return n; 244 } 245 246 int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, 247 __u64 key, __u64 *keys, __u64 *ptrs, 248 int n, __u64 low, __u64 high) 249 { 250 struct nilfs_direct *direct; 251 __le64 *dptrs; 252 int ret, i, j; 253 254 /* no need to allocate any resource for conversion */ 255 256 /* delete */ 257 ret = bmap->b_ops->bop_delete(bmap, key); 258 if (ret < 0) 259 return ret; 260 261 /* free resources */ 262 if (bmap->b_ops->bop_clear != NULL) 263 bmap->b_ops->bop_clear(bmap); 264 265 /* convert */ 266 direct = (struct nilfs_direct *)bmap; 267 dptrs = nilfs_direct_dptrs(direct); 268 for (i = 0, j = 0; i < NILFS_DIRECT_NBLOCKS; i++) { 269 if ((j < n) && (i == keys[j])) { 270 dptrs[i] = (i != key) ? 271 nilfs_bmap_ptr_to_dptr(ptrs[j]) : 272 NILFS_BMAP_INVALID_PTR; 273 j++; 274 } else 275 dptrs[i] = NILFS_BMAP_INVALID_PTR; 276 } 277 278 nilfs_direct_init(bmap, low, high); 279 280 return 0; 281 } 282 283 static int nilfs_direct_propagate_v(struct nilfs_direct *direct, 284 struct buffer_head *bh) 285 { 286 union nilfs_bmap_ptr_req oldreq, newreq; 287 __u64 key; 288 __u64 ptr; 289 int ret; 290 291 key = nilfs_bmap_data_get_key(&direct->d_bmap, bh); 292 ptr = nilfs_direct_get_ptr(direct, key); 293 if (!buffer_nilfs_volatile(bh)) { 294 oldreq.bpr_ptr = ptr; 295 newreq.bpr_ptr = ptr; 296 ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq, 297 &newreq); 298 if (ret < 0) 299 return ret; 300 nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq); 301 set_buffer_nilfs_volatile(bh); 302 nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr); 303 } else 304 ret = nilfs_bmap_mark_dirty(&direct->d_bmap, ptr); 305 306 return ret; 307 } 308 309 static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, 310 struct buffer_head *bh) 311 { 312 struct nilfs_direct *direct; 313 314 direct = (struct nilfs_direct *)bmap; 315 return (direct->d_ops->dop_propagate != NULL) ? 316 direct->d_ops->dop_propagate(direct, bh) : 317 0; 318 } 319 320 static int nilfs_direct_assign_v(struct nilfs_direct *direct, 321 __u64 key, __u64 ptr, 322 struct buffer_head **bh, 323 sector_t blocknr, 324 union nilfs_binfo *binfo) 325 { 326 union nilfs_bmap_ptr_req req; 327 int ret; 328 329 req.bpr_ptr = ptr; 330 ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr( 331 &direct->d_bmap, &req); 332 if (ret < 0) 333 return ret; 334 direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap, 335 &req, blocknr); 336 337 binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); 338 binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); 339 340 return 0; 341 } 342 343 static int nilfs_direct_assign_p(struct nilfs_direct *direct, 344 __u64 key, __u64 ptr, 345 struct buffer_head **bh, 346 sector_t blocknr, 347 union nilfs_binfo *binfo) 348 { 349 nilfs_direct_set_ptr(direct, key, blocknr); 350 351 binfo->bi_dat.bi_blkoff = nilfs_bmap_key_to_dkey(key); 352 binfo->bi_dat.bi_level = 0; 353 354 return 0; 355 } 356 357 static int nilfs_direct_assign(struct nilfs_bmap *bmap, 358 struct buffer_head **bh, 359 sector_t blocknr, 360 union nilfs_binfo *binfo) 361 { 362 struct nilfs_direct *direct; 363 __u64 key; 364 __u64 ptr; 365 366 direct = (struct nilfs_direct *)bmap; 367 key = nilfs_bmap_data_get_key(bmap, *bh); 368 if (unlikely(key > NILFS_DIRECT_KEY_MAX)) { 369 printk(KERN_CRIT "%s: invalid key: %llu\n", __func__, 370 (unsigned long long)key); 371 return -EINVAL; 372 } 373 ptr = nilfs_direct_get_ptr(direct, key); 374 if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) { 375 printk(KERN_CRIT "%s: invalid pointer: %llu\n", __func__, 376 (unsigned long long)ptr); 377 return -EINVAL; 378 } 379 380 return direct->d_ops->dop_assign(direct, key, ptr, bh, 381 blocknr, binfo); 382 } 383 384 static const struct nilfs_bmap_operations nilfs_direct_ops = { 385 .bop_lookup = nilfs_direct_lookup, 386 .bop_insert = nilfs_direct_insert, 387 .bop_delete = nilfs_direct_delete, 388 .bop_clear = NULL, 389 390 .bop_propagate = nilfs_direct_propagate, 391 392 .bop_lookup_dirty_buffers = NULL, 393 394 .bop_assign = nilfs_direct_assign, 395 .bop_mark = NULL, 396 397 .bop_last_key = nilfs_direct_last_key, 398 .bop_check_insert = nilfs_direct_check_insert, 399 .bop_check_delete = NULL, 400 .bop_gather_data = nilfs_direct_gather_data, 401 }; 402 403 404 static const struct nilfs_direct_operations nilfs_direct_ops_v = { 405 .dop_find_target = nilfs_direct_find_target_v, 406 .dop_set_target = nilfs_direct_set_target_v, 407 .dop_propagate = nilfs_direct_propagate_v, 408 .dop_assign = nilfs_direct_assign_v, 409 }; 410 411 static const struct nilfs_direct_operations nilfs_direct_ops_p = { 412 .dop_find_target = NULL, 413 .dop_set_target = NULL, 414 .dop_propagate = NULL, 415 .dop_assign = nilfs_direct_assign_p, 416 }; 417 418 int nilfs_direct_init(struct nilfs_bmap *bmap, __u64 low, __u64 high) 419 { 420 struct nilfs_direct *direct; 421 422 direct = (struct nilfs_direct *)bmap; 423 bmap->b_ops = &nilfs_direct_ops; 424 bmap->b_low = low; 425 bmap->b_high = high; 426 switch (bmap->b_inode->i_ino) { 427 case NILFS_DAT_INO: 428 direct->d_ops = &nilfs_direct_ops_p; 429 break; 430 default: 431 direct->d_ops = &nilfs_direct_ops_v; 432 break; 433 } 434 435 return 0; 436 } 437