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 * Written by Koji Sato. 17 */ 18 19 #include <linux/errno.h> 20 #include "nilfs.h" 21 #include "page.h" 22 #include "direct.h" 23 #include "alloc.h" 24 #include "dat.h" 25 26 static inline __le64 *nilfs_direct_dptrs(const struct nilfs_bmap *direct) 27 { 28 return (__le64 *) 29 ((struct nilfs_direct_node *)direct->b_u.u_data + 1); 30 } 31 32 static inline __u64 33 nilfs_direct_get_ptr(const struct nilfs_bmap *direct, __u64 key) 34 { 35 return le64_to_cpu(*(nilfs_direct_dptrs(direct) + key)); 36 } 37 38 static inline void nilfs_direct_set_ptr(struct nilfs_bmap *direct, 39 __u64 key, __u64 ptr) 40 { 41 *(nilfs_direct_dptrs(direct) + key) = cpu_to_le64(ptr); 42 } 43 44 static int nilfs_direct_lookup(const struct nilfs_bmap *direct, 45 __u64 key, int level, __u64 *ptrp) 46 { 47 __u64 ptr; 48 49 if (key > NILFS_DIRECT_KEY_MAX || level != 1) 50 return -ENOENT; 51 ptr = nilfs_direct_get_ptr(direct, key); 52 if (ptr == NILFS_BMAP_INVALID_PTR) 53 return -ENOENT; 54 55 *ptrp = ptr; 56 return 0; 57 } 58 59 static int nilfs_direct_lookup_contig(const struct nilfs_bmap *direct, 60 __u64 key, __u64 *ptrp, 61 unsigned int maxblocks) 62 { 63 struct inode *dat = NULL; 64 __u64 ptr, ptr2; 65 sector_t blocknr; 66 int ret, cnt; 67 68 if (key > NILFS_DIRECT_KEY_MAX) 69 return -ENOENT; 70 ptr = nilfs_direct_get_ptr(direct, key); 71 if (ptr == NILFS_BMAP_INVALID_PTR) 72 return -ENOENT; 73 74 if (NILFS_BMAP_USE_VBN(direct)) { 75 dat = nilfs_bmap_get_dat(direct); 76 ret = nilfs_dat_translate(dat, ptr, &blocknr); 77 if (ret < 0) 78 return ret; 79 ptr = blocknr; 80 } 81 82 maxblocks = min_t(unsigned int, maxblocks, 83 NILFS_DIRECT_KEY_MAX - key + 1); 84 for (cnt = 1; cnt < maxblocks && 85 (ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) != 86 NILFS_BMAP_INVALID_PTR; 87 cnt++) { 88 if (dat) { 89 ret = nilfs_dat_translate(dat, ptr2, &blocknr); 90 if (ret < 0) 91 return ret; 92 ptr2 = blocknr; 93 } 94 if (ptr2 != ptr + cnt) 95 break; 96 } 97 *ptrp = ptr; 98 return cnt; 99 } 100 101 static __u64 102 nilfs_direct_find_target_v(const struct nilfs_bmap *direct, __u64 key) 103 { 104 __u64 ptr; 105 106 ptr = nilfs_bmap_find_target_seq(direct, key); 107 if (ptr != NILFS_BMAP_INVALID_PTR) 108 /* sequential access */ 109 return ptr; 110 111 /* block group */ 112 return nilfs_bmap_find_target_in_group(direct); 113 } 114 115 static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) 116 { 117 union nilfs_bmap_ptr_req req; 118 struct inode *dat = NULL; 119 struct buffer_head *bh; 120 int ret; 121 122 if (key > NILFS_DIRECT_KEY_MAX) 123 return -ENOENT; 124 if (nilfs_direct_get_ptr(bmap, key) != NILFS_BMAP_INVALID_PTR) 125 return -EEXIST; 126 127 if (NILFS_BMAP_USE_VBN(bmap)) { 128 req.bpr_ptr = nilfs_direct_find_target_v(bmap, key); 129 dat = nilfs_bmap_get_dat(bmap); 130 } 131 ret = nilfs_bmap_prepare_alloc_ptr(bmap, &req, dat); 132 if (!ret) { 133 /* ptr must be a pointer to a buffer head. */ 134 bh = (struct buffer_head *)((unsigned long)ptr); 135 set_buffer_nilfs_volatile(bh); 136 137 nilfs_bmap_commit_alloc_ptr(bmap, &req, dat); 138 nilfs_direct_set_ptr(bmap, key, req.bpr_ptr); 139 140 if (!nilfs_bmap_dirty(bmap)) 141 nilfs_bmap_set_dirty(bmap); 142 143 if (NILFS_BMAP_USE_VBN(bmap)) 144 nilfs_bmap_set_target_v(bmap, key, req.bpr_ptr); 145 146 nilfs_inode_add_blocks(bmap->b_inode, 1); 147 } 148 return ret; 149 } 150 151 static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key) 152 { 153 union nilfs_bmap_ptr_req req; 154 struct inode *dat; 155 int ret; 156 157 if (key > NILFS_DIRECT_KEY_MAX || 158 nilfs_direct_get_ptr(bmap, key) == NILFS_BMAP_INVALID_PTR) 159 return -ENOENT; 160 161 dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL; 162 req.bpr_ptr = nilfs_direct_get_ptr(bmap, key); 163 164 ret = nilfs_bmap_prepare_end_ptr(bmap, &req, dat); 165 if (!ret) { 166 nilfs_bmap_commit_end_ptr(bmap, &req, dat); 167 nilfs_direct_set_ptr(bmap, key, NILFS_BMAP_INVALID_PTR); 168 nilfs_inode_sub_blocks(bmap->b_inode, 1); 169 } 170 return ret; 171 } 172 173 static int nilfs_direct_seek_key(const struct nilfs_bmap *direct, __u64 start, 174 __u64 *keyp) 175 { 176 __u64 key; 177 178 for (key = start; key <= NILFS_DIRECT_KEY_MAX; key++) { 179 if (nilfs_direct_get_ptr(direct, key) != 180 NILFS_BMAP_INVALID_PTR) { 181 *keyp = key; 182 return 0; 183 } 184 } 185 return -ENOENT; 186 } 187 188 static int nilfs_direct_last_key(const struct nilfs_bmap *direct, __u64 *keyp) 189 { 190 __u64 key, lastkey; 191 192 lastkey = NILFS_DIRECT_KEY_MAX + 1; 193 for (key = NILFS_DIRECT_KEY_MIN; key <= NILFS_DIRECT_KEY_MAX; key++) 194 if (nilfs_direct_get_ptr(direct, key) != 195 NILFS_BMAP_INVALID_PTR) 196 lastkey = key; 197 198 if (lastkey == NILFS_DIRECT_KEY_MAX + 1) 199 return -ENOENT; 200 201 *keyp = lastkey; 202 203 return 0; 204 } 205 206 static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key) 207 { 208 return key > NILFS_DIRECT_KEY_MAX; 209 } 210 211 static int nilfs_direct_gather_data(struct nilfs_bmap *direct, 212 __u64 *keys, __u64 *ptrs, int nitems) 213 { 214 __u64 key; 215 __u64 ptr; 216 int n; 217 218 if (nitems > NILFS_DIRECT_NBLOCKS) 219 nitems = NILFS_DIRECT_NBLOCKS; 220 n = 0; 221 for (key = 0; key < nitems; key++) { 222 ptr = nilfs_direct_get_ptr(direct, key); 223 if (ptr != NILFS_BMAP_INVALID_PTR) { 224 keys[n] = key; 225 ptrs[n] = ptr; 226 n++; 227 } 228 } 229 return n; 230 } 231 232 int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, 233 __u64 key, __u64 *keys, __u64 *ptrs, int n) 234 { 235 __le64 *dptrs; 236 int ret, i, j; 237 238 /* no need to allocate any resource for conversion */ 239 240 /* delete */ 241 ret = bmap->b_ops->bop_delete(bmap, key); 242 if (ret < 0) 243 return ret; 244 245 /* free resources */ 246 if (bmap->b_ops->bop_clear != NULL) 247 bmap->b_ops->bop_clear(bmap); 248 249 /* convert */ 250 dptrs = nilfs_direct_dptrs(bmap); 251 for (i = 0, j = 0; i < NILFS_DIRECT_NBLOCKS; i++) { 252 if ((j < n) && (i == keys[j])) { 253 dptrs[i] = (i != key) ? 254 cpu_to_le64(ptrs[j]) : 255 NILFS_BMAP_INVALID_PTR; 256 j++; 257 } else 258 dptrs[i] = NILFS_BMAP_INVALID_PTR; 259 } 260 261 nilfs_direct_init(bmap); 262 return 0; 263 } 264 265 static int nilfs_direct_propagate(struct nilfs_bmap *bmap, 266 struct buffer_head *bh) 267 { 268 struct nilfs_palloc_req oldreq, newreq; 269 struct inode *dat; 270 __u64 key; 271 __u64 ptr; 272 int ret; 273 274 if (!NILFS_BMAP_USE_VBN(bmap)) 275 return 0; 276 277 dat = nilfs_bmap_get_dat(bmap); 278 key = nilfs_bmap_data_get_key(bmap, bh); 279 ptr = nilfs_direct_get_ptr(bmap, key); 280 if (!buffer_nilfs_volatile(bh)) { 281 oldreq.pr_entry_nr = ptr; 282 newreq.pr_entry_nr = ptr; 283 ret = nilfs_dat_prepare_update(dat, &oldreq, &newreq); 284 if (ret < 0) 285 return ret; 286 nilfs_dat_commit_update(dat, &oldreq, &newreq, 287 bmap->b_ptr_type == NILFS_BMAP_PTR_VS); 288 set_buffer_nilfs_volatile(bh); 289 nilfs_direct_set_ptr(bmap, key, newreq.pr_entry_nr); 290 } else 291 ret = nilfs_dat_mark_dirty(dat, ptr); 292 293 return ret; 294 } 295 296 static int nilfs_direct_assign_v(struct nilfs_bmap *direct, 297 __u64 key, __u64 ptr, 298 struct buffer_head **bh, 299 sector_t blocknr, 300 union nilfs_binfo *binfo) 301 { 302 struct inode *dat = nilfs_bmap_get_dat(direct); 303 union nilfs_bmap_ptr_req req; 304 int ret; 305 306 req.bpr_ptr = ptr; 307 ret = nilfs_dat_prepare_start(dat, &req.bpr_req); 308 if (!ret) { 309 nilfs_dat_commit_start(dat, &req.bpr_req, blocknr); 310 binfo->bi_v.bi_vblocknr = cpu_to_le64(ptr); 311 binfo->bi_v.bi_blkoff = cpu_to_le64(key); 312 } 313 return ret; 314 } 315 316 static int nilfs_direct_assign_p(struct nilfs_bmap *direct, 317 __u64 key, __u64 ptr, 318 struct buffer_head **bh, 319 sector_t blocknr, 320 union nilfs_binfo *binfo) 321 { 322 nilfs_direct_set_ptr(direct, key, blocknr); 323 324 binfo->bi_dat.bi_blkoff = cpu_to_le64(key); 325 binfo->bi_dat.bi_level = 0; 326 327 return 0; 328 } 329 330 static int nilfs_direct_assign(struct nilfs_bmap *bmap, 331 struct buffer_head **bh, 332 sector_t blocknr, 333 union nilfs_binfo *binfo) 334 { 335 __u64 key; 336 __u64 ptr; 337 338 key = nilfs_bmap_data_get_key(bmap, *bh); 339 if (unlikely(key > NILFS_DIRECT_KEY_MAX)) { 340 nilfs_msg(bmap->b_inode->i_sb, KERN_CRIT, 341 "%s (ino=%lu): invalid key: %llu", __func__, 342 bmap->b_inode->i_ino, (unsigned long long)key); 343 return -EINVAL; 344 } 345 ptr = nilfs_direct_get_ptr(bmap, key); 346 if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) { 347 nilfs_msg(bmap->b_inode->i_sb, KERN_CRIT, 348 "%s (ino=%lu): invalid pointer: %llu", __func__, 349 bmap->b_inode->i_ino, (unsigned long long)ptr); 350 return -EINVAL; 351 } 352 353 return NILFS_BMAP_USE_VBN(bmap) ? 354 nilfs_direct_assign_v(bmap, key, ptr, bh, blocknr, binfo) : 355 nilfs_direct_assign_p(bmap, key, ptr, bh, blocknr, binfo); 356 } 357 358 static const struct nilfs_bmap_operations nilfs_direct_ops = { 359 .bop_lookup = nilfs_direct_lookup, 360 .bop_lookup_contig = nilfs_direct_lookup_contig, 361 .bop_insert = nilfs_direct_insert, 362 .bop_delete = nilfs_direct_delete, 363 .bop_clear = NULL, 364 365 .bop_propagate = nilfs_direct_propagate, 366 367 .bop_lookup_dirty_buffers = NULL, 368 369 .bop_assign = nilfs_direct_assign, 370 .bop_mark = NULL, 371 372 .bop_seek_key = nilfs_direct_seek_key, 373 .bop_last_key = nilfs_direct_last_key, 374 375 .bop_check_insert = nilfs_direct_check_insert, 376 .bop_check_delete = NULL, 377 .bop_gather_data = nilfs_direct_gather_data, 378 }; 379 380 381 int nilfs_direct_init(struct nilfs_bmap *bmap) 382 { 383 bmap->b_ops = &nilfs_direct_ops; 384 return 0; 385 } 386