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