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