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