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