Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * NILFS direct block pointer.
0004  *
0005  * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
0006  *
0007  * Written by Koji Sato.
0008  */
0009 
0010 #include <linux/errno.h>
0011 #include "nilfs.h"
0012 #include "page.h"
0013 #include "direct.h"
0014 #include "alloc.h"
0015 #include "dat.h"
0016 
0017 static inline __le64 *nilfs_direct_dptrs(const struct nilfs_bmap *direct)
0018 {
0019     return (__le64 *)
0020         ((struct nilfs_direct_node *)direct->b_u.u_data + 1);
0021 }
0022 
0023 static inline __u64
0024 nilfs_direct_get_ptr(const struct nilfs_bmap *direct, __u64 key)
0025 {
0026     return le64_to_cpu(*(nilfs_direct_dptrs(direct) + key));
0027 }
0028 
0029 static inline void nilfs_direct_set_ptr(struct nilfs_bmap *direct,
0030                     __u64 key, __u64 ptr)
0031 {
0032     *(nilfs_direct_dptrs(direct) + key) = cpu_to_le64(ptr);
0033 }
0034 
0035 static int nilfs_direct_lookup(const struct nilfs_bmap *direct,
0036                    __u64 key, int level, __u64 *ptrp)
0037 {
0038     __u64 ptr;
0039 
0040     if (key > NILFS_DIRECT_KEY_MAX || level != 1)
0041         return -ENOENT;
0042     ptr = nilfs_direct_get_ptr(direct, key);
0043     if (ptr == NILFS_BMAP_INVALID_PTR)
0044         return -ENOENT;
0045 
0046     *ptrp = ptr;
0047     return 0;
0048 }
0049 
0050 static int nilfs_direct_lookup_contig(const struct nilfs_bmap *direct,
0051                       __u64 key, __u64 *ptrp,
0052                       unsigned int maxblocks)
0053 {
0054     struct inode *dat = NULL;
0055     __u64 ptr, ptr2;
0056     sector_t blocknr;
0057     int ret, cnt;
0058 
0059     if (key > NILFS_DIRECT_KEY_MAX)
0060         return -ENOENT;
0061     ptr = nilfs_direct_get_ptr(direct, key);
0062     if (ptr == NILFS_BMAP_INVALID_PTR)
0063         return -ENOENT;
0064 
0065     if (NILFS_BMAP_USE_VBN(direct)) {
0066         dat = nilfs_bmap_get_dat(direct);
0067         ret = nilfs_dat_translate(dat, ptr, &blocknr);
0068         if (ret < 0)
0069             return ret;
0070         ptr = blocknr;
0071     }
0072 
0073     maxblocks = min_t(unsigned int, maxblocks,
0074               NILFS_DIRECT_KEY_MAX - key + 1);
0075     for (cnt = 1; cnt < maxblocks &&
0076              (ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) !=
0077              NILFS_BMAP_INVALID_PTR;
0078          cnt++) {
0079         if (dat) {
0080             ret = nilfs_dat_translate(dat, ptr2, &blocknr);
0081             if (ret < 0)
0082                 return ret;
0083             ptr2 = blocknr;
0084         }
0085         if (ptr2 != ptr + cnt)
0086             break;
0087     }
0088     *ptrp = ptr;
0089     return cnt;
0090 }
0091 
0092 static __u64
0093 nilfs_direct_find_target_v(const struct nilfs_bmap *direct, __u64 key)
0094 {
0095     __u64 ptr;
0096 
0097     ptr = nilfs_bmap_find_target_seq(direct, key);
0098     if (ptr != NILFS_BMAP_INVALID_PTR)
0099         /* sequential access */
0100         return ptr;
0101 
0102     /* block group */
0103     return nilfs_bmap_find_target_in_group(direct);
0104 }
0105 
0106 static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
0107 {
0108     union nilfs_bmap_ptr_req req;
0109     struct inode *dat = NULL;
0110     struct buffer_head *bh;
0111     int ret;
0112 
0113     if (key > NILFS_DIRECT_KEY_MAX)
0114         return -ENOENT;
0115     if (nilfs_direct_get_ptr(bmap, key) != NILFS_BMAP_INVALID_PTR)
0116         return -EEXIST;
0117 
0118     if (NILFS_BMAP_USE_VBN(bmap)) {
0119         req.bpr_ptr = nilfs_direct_find_target_v(bmap, key);
0120         dat = nilfs_bmap_get_dat(bmap);
0121     }
0122     ret = nilfs_bmap_prepare_alloc_ptr(bmap, &req, dat);
0123     if (!ret) {
0124         /* ptr must be a pointer to a buffer head. */
0125         bh = (struct buffer_head *)((unsigned long)ptr);
0126         set_buffer_nilfs_volatile(bh);
0127 
0128         nilfs_bmap_commit_alloc_ptr(bmap, &req, dat);
0129         nilfs_direct_set_ptr(bmap, key, req.bpr_ptr);
0130 
0131         if (!nilfs_bmap_dirty(bmap))
0132             nilfs_bmap_set_dirty(bmap);
0133 
0134         if (NILFS_BMAP_USE_VBN(bmap))
0135             nilfs_bmap_set_target_v(bmap, key, req.bpr_ptr);
0136 
0137         nilfs_inode_add_blocks(bmap->b_inode, 1);
0138     }
0139     return ret;
0140 }
0141 
0142 static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key)
0143 {
0144     union nilfs_bmap_ptr_req req;
0145     struct inode *dat;
0146     int ret;
0147 
0148     if (key > NILFS_DIRECT_KEY_MAX ||
0149         nilfs_direct_get_ptr(bmap, key) == NILFS_BMAP_INVALID_PTR)
0150         return -ENOENT;
0151 
0152     dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL;
0153     req.bpr_ptr = nilfs_direct_get_ptr(bmap, key);
0154 
0155     ret = nilfs_bmap_prepare_end_ptr(bmap, &req, dat);
0156     if (!ret) {
0157         nilfs_bmap_commit_end_ptr(bmap, &req, dat);
0158         nilfs_direct_set_ptr(bmap, key, NILFS_BMAP_INVALID_PTR);
0159         nilfs_inode_sub_blocks(bmap->b_inode, 1);
0160     }
0161     return ret;
0162 }
0163 
0164 static int nilfs_direct_seek_key(const struct nilfs_bmap *direct, __u64 start,
0165                  __u64 *keyp)
0166 {
0167     __u64 key;
0168 
0169     for (key = start; key <= NILFS_DIRECT_KEY_MAX; key++) {
0170         if (nilfs_direct_get_ptr(direct, key) !=
0171             NILFS_BMAP_INVALID_PTR) {
0172             *keyp = key;
0173             return 0;
0174         }
0175     }
0176     return -ENOENT;
0177 }
0178 
0179 static int nilfs_direct_last_key(const struct nilfs_bmap *direct, __u64 *keyp)
0180 {
0181     __u64 key, lastkey;
0182 
0183     lastkey = NILFS_DIRECT_KEY_MAX + 1;
0184     for (key = NILFS_DIRECT_KEY_MIN; key <= NILFS_DIRECT_KEY_MAX; key++)
0185         if (nilfs_direct_get_ptr(direct, key) !=
0186             NILFS_BMAP_INVALID_PTR)
0187             lastkey = key;
0188 
0189     if (lastkey == NILFS_DIRECT_KEY_MAX + 1)
0190         return -ENOENT;
0191 
0192     *keyp = lastkey;
0193 
0194     return 0;
0195 }
0196 
0197 static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key)
0198 {
0199     return key > NILFS_DIRECT_KEY_MAX;
0200 }
0201 
0202 static int nilfs_direct_gather_data(struct nilfs_bmap *direct,
0203                     __u64 *keys, __u64 *ptrs, int nitems)
0204 {
0205     __u64 key;
0206     __u64 ptr;
0207     int n;
0208 
0209     if (nitems > NILFS_DIRECT_NBLOCKS)
0210         nitems = NILFS_DIRECT_NBLOCKS;
0211     n = 0;
0212     for (key = 0; key < nitems; key++) {
0213         ptr = nilfs_direct_get_ptr(direct, key);
0214         if (ptr != NILFS_BMAP_INVALID_PTR) {
0215             keys[n] = key;
0216             ptrs[n] = ptr;
0217             n++;
0218         }
0219     }
0220     return n;
0221 }
0222 
0223 int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
0224                     __u64 key, __u64 *keys, __u64 *ptrs, int n)
0225 {
0226     __le64 *dptrs;
0227     int ret, i, j;
0228 
0229     /* no need to allocate any resource for conversion */
0230 
0231     /* delete */
0232     ret = bmap->b_ops->bop_delete(bmap, key);
0233     if (ret < 0)
0234         return ret;
0235 
0236     /* free resources */
0237     if (bmap->b_ops->bop_clear != NULL)
0238         bmap->b_ops->bop_clear(bmap);
0239 
0240     /* convert */
0241     dptrs = nilfs_direct_dptrs(bmap);
0242     for (i = 0, j = 0; i < NILFS_DIRECT_NBLOCKS; i++) {
0243         if ((j < n) && (i == keys[j])) {
0244             dptrs[i] = (i != key) ?
0245                 cpu_to_le64(ptrs[j]) :
0246                 NILFS_BMAP_INVALID_PTR;
0247             j++;
0248         } else
0249             dptrs[i] = NILFS_BMAP_INVALID_PTR;
0250     }
0251 
0252     nilfs_direct_init(bmap);
0253     return 0;
0254 }
0255 
0256 static int nilfs_direct_propagate(struct nilfs_bmap *bmap,
0257                   struct buffer_head *bh)
0258 {
0259     struct nilfs_palloc_req oldreq, newreq;
0260     struct inode *dat;
0261     __u64 key;
0262     __u64 ptr;
0263     int ret;
0264 
0265     if (!NILFS_BMAP_USE_VBN(bmap))
0266         return 0;
0267 
0268     dat = nilfs_bmap_get_dat(bmap);
0269     key = nilfs_bmap_data_get_key(bmap, bh);
0270     ptr = nilfs_direct_get_ptr(bmap, key);
0271     if (!buffer_nilfs_volatile(bh)) {
0272         oldreq.pr_entry_nr = ptr;
0273         newreq.pr_entry_nr = ptr;
0274         ret = nilfs_dat_prepare_update(dat, &oldreq, &newreq);
0275         if (ret < 0)
0276             return ret;
0277         nilfs_dat_commit_update(dat, &oldreq, &newreq,
0278                     bmap->b_ptr_type == NILFS_BMAP_PTR_VS);
0279         set_buffer_nilfs_volatile(bh);
0280         nilfs_direct_set_ptr(bmap, key, newreq.pr_entry_nr);
0281     } else
0282         ret = nilfs_dat_mark_dirty(dat, ptr);
0283 
0284     return ret;
0285 }
0286 
0287 static int nilfs_direct_assign_v(struct nilfs_bmap *direct,
0288                  __u64 key, __u64 ptr,
0289                  struct buffer_head **bh,
0290                  sector_t blocknr,
0291                  union nilfs_binfo *binfo)
0292 {
0293     struct inode *dat = nilfs_bmap_get_dat(direct);
0294     union nilfs_bmap_ptr_req req;
0295     int ret;
0296 
0297     req.bpr_ptr = ptr;
0298     ret = nilfs_dat_prepare_start(dat, &req.bpr_req);
0299     if (!ret) {
0300         nilfs_dat_commit_start(dat, &req.bpr_req, blocknr);
0301         binfo->bi_v.bi_vblocknr = cpu_to_le64(ptr);
0302         binfo->bi_v.bi_blkoff = cpu_to_le64(key);
0303     }
0304     return ret;
0305 }
0306 
0307 static int nilfs_direct_assign_p(struct nilfs_bmap *direct,
0308                  __u64 key, __u64 ptr,
0309                  struct buffer_head **bh,
0310                  sector_t blocknr,
0311                  union nilfs_binfo *binfo)
0312 {
0313     nilfs_direct_set_ptr(direct, key, blocknr);
0314 
0315     binfo->bi_dat.bi_blkoff = cpu_to_le64(key);
0316     binfo->bi_dat.bi_level = 0;
0317 
0318     return 0;
0319 }
0320 
0321 static int nilfs_direct_assign(struct nilfs_bmap *bmap,
0322                    struct buffer_head **bh,
0323                    sector_t blocknr,
0324                    union nilfs_binfo *binfo)
0325 {
0326     __u64 key;
0327     __u64 ptr;
0328 
0329     key = nilfs_bmap_data_get_key(bmap, *bh);
0330     if (unlikely(key > NILFS_DIRECT_KEY_MAX)) {
0331         nilfs_crit(bmap->b_inode->i_sb,
0332                "%s (ino=%lu): invalid key: %llu",
0333                __func__,
0334                bmap->b_inode->i_ino, (unsigned long long)key);
0335         return -EINVAL;
0336     }
0337     ptr = nilfs_direct_get_ptr(bmap, key);
0338     if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) {
0339         nilfs_crit(bmap->b_inode->i_sb,
0340                "%s (ino=%lu): invalid pointer: %llu",
0341                __func__,
0342                bmap->b_inode->i_ino, (unsigned long long)ptr);
0343         return -EINVAL;
0344     }
0345 
0346     return NILFS_BMAP_USE_VBN(bmap) ?
0347         nilfs_direct_assign_v(bmap, key, ptr, bh, blocknr, binfo) :
0348         nilfs_direct_assign_p(bmap, key, ptr, bh, blocknr, binfo);
0349 }
0350 
0351 static const struct nilfs_bmap_operations nilfs_direct_ops = {
0352     .bop_lookup     =   nilfs_direct_lookup,
0353     .bop_lookup_contig  =   nilfs_direct_lookup_contig,
0354     .bop_insert     =   nilfs_direct_insert,
0355     .bop_delete     =   nilfs_direct_delete,
0356     .bop_clear      =   NULL,
0357 
0358     .bop_propagate      =   nilfs_direct_propagate,
0359 
0360     .bop_lookup_dirty_buffers   =   NULL,
0361 
0362     .bop_assign     =   nilfs_direct_assign,
0363     .bop_mark       =   NULL,
0364 
0365     .bop_seek_key       =   nilfs_direct_seek_key,
0366     .bop_last_key       =   nilfs_direct_last_key,
0367 
0368     .bop_check_insert   =   nilfs_direct_check_insert,
0369     .bop_check_delete   =   NULL,
0370     .bop_gather_data    =   nilfs_direct_gather_data,
0371 };
0372 
0373 
0374 int nilfs_direct_init(struct nilfs_bmap *bmap)
0375 {
0376     bmap->b_ops = &nilfs_direct_ops;
0377     return 0;
0378 }