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 * 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
  26static 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
  32static inline __u64
  33nilfs_direct_get_ptr(const struct nilfs_bmap *direct, __u64 key)
  34{
  35        return le64_to_cpu(*(nilfs_direct_dptrs(direct) + key));
  36}
  37
  38static 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
  44static 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
  59static 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
 101static __u64
 102nilfs_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
 115static 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
 151static 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
 173static 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
 188static 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
 206static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key)
 207{
 208        return key > NILFS_DIRECT_KEY_MAX;
 209}
 210
 211static 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
 232int 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
 265static 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
 296static 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
 316static 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
 330static 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
 358static 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
 381int nilfs_direct_init(struct nilfs_bmap *bmap)
 382{
 383        bmap->b_ops = &nilfs_direct_ops;
 384        return 0;
 385}
 386