linux/fs/nilfs2/dat.c
<<
>>
Prefs
   1/*
   2 * dat.c - NILFS disk address translation.
   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/types.h>
  20#include <linux/buffer_head.h>
  21#include <linux/string.h>
  22#include <linux/errno.h>
  23#include "nilfs.h"
  24#include "mdt.h"
  25#include "alloc.h"
  26#include "dat.h"
  27
  28
  29#define NILFS_CNO_MIN   ((__u64)1)
  30#define NILFS_CNO_MAX   (~(__u64)0)
  31
  32/**
  33 * struct nilfs_dat_info - on-memory private data of DAT file
  34 * @mi: on-memory private data of metadata file
  35 * @palloc_cache: persistent object allocator cache of DAT file
  36 * @shadow: shadow map of DAT file
  37 */
  38struct nilfs_dat_info {
  39        struct nilfs_mdt_info mi;
  40        struct nilfs_palloc_cache palloc_cache;
  41        struct nilfs_shadow_map shadow;
  42};
  43
  44static inline struct nilfs_dat_info *NILFS_DAT_I(struct inode *dat)
  45{
  46        return (struct nilfs_dat_info *)NILFS_MDT(dat);
  47}
  48
  49static int nilfs_dat_prepare_entry(struct inode *dat,
  50                                   struct nilfs_palloc_req *req, int create)
  51{
  52        return nilfs_palloc_get_entry_block(dat, req->pr_entry_nr,
  53                                            create, &req->pr_entry_bh);
  54}
  55
  56static void nilfs_dat_commit_entry(struct inode *dat,
  57                                   struct nilfs_palloc_req *req)
  58{
  59        mark_buffer_dirty(req->pr_entry_bh);
  60        nilfs_mdt_mark_dirty(dat);
  61        brelse(req->pr_entry_bh);
  62}
  63
  64static void nilfs_dat_abort_entry(struct inode *dat,
  65                                  struct nilfs_palloc_req *req)
  66{
  67        brelse(req->pr_entry_bh);
  68}
  69
  70int nilfs_dat_prepare_alloc(struct inode *dat, struct nilfs_palloc_req *req)
  71{
  72        int ret;
  73
  74        ret = nilfs_palloc_prepare_alloc_entry(dat, req);
  75        if (ret < 0)
  76                return ret;
  77
  78        ret = nilfs_dat_prepare_entry(dat, req, 1);
  79        if (ret < 0)
  80                nilfs_palloc_abort_alloc_entry(dat, req);
  81
  82        return ret;
  83}
  84
  85void nilfs_dat_commit_alloc(struct inode *dat, struct nilfs_palloc_req *req)
  86{
  87        struct nilfs_dat_entry *entry;
  88        void *kaddr;
  89
  90        kaddr = kmap_atomic(req->pr_entry_bh->b_page);
  91        entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
  92                                             req->pr_entry_bh, kaddr);
  93        entry->de_start = cpu_to_le64(NILFS_CNO_MIN);
  94        entry->de_end = cpu_to_le64(NILFS_CNO_MAX);
  95        entry->de_blocknr = cpu_to_le64(0);
  96        kunmap_atomic(kaddr);
  97
  98        nilfs_palloc_commit_alloc_entry(dat, req);
  99        nilfs_dat_commit_entry(dat, req);
 100}
 101
 102void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req)
 103{
 104        nilfs_dat_abort_entry(dat, req);
 105        nilfs_palloc_abort_alloc_entry(dat, req);
 106}
 107
 108static void nilfs_dat_commit_free(struct inode *dat,
 109                                  struct nilfs_palloc_req *req)
 110{
 111        struct nilfs_dat_entry *entry;
 112        void *kaddr;
 113
 114        kaddr = kmap_atomic(req->pr_entry_bh->b_page);
 115        entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
 116                                             req->pr_entry_bh, kaddr);
 117        entry->de_start = cpu_to_le64(NILFS_CNO_MIN);
 118        entry->de_end = cpu_to_le64(NILFS_CNO_MIN);
 119        entry->de_blocknr = cpu_to_le64(0);
 120        kunmap_atomic(kaddr);
 121
 122        nilfs_dat_commit_entry(dat, req);
 123        nilfs_palloc_commit_free_entry(dat, req);
 124}
 125
 126int nilfs_dat_prepare_start(struct inode *dat, struct nilfs_palloc_req *req)
 127{
 128        int ret;
 129
 130        ret = nilfs_dat_prepare_entry(dat, req, 0);
 131        WARN_ON(ret == -ENOENT);
 132        return ret;
 133}
 134
 135void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req,
 136                            sector_t blocknr)
 137{
 138        struct nilfs_dat_entry *entry;
 139        void *kaddr;
 140
 141        kaddr = kmap_atomic(req->pr_entry_bh->b_page);
 142        entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
 143                                             req->pr_entry_bh, kaddr);
 144        entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat));
 145        entry->de_blocknr = cpu_to_le64(blocknr);
 146        kunmap_atomic(kaddr);
 147
 148        nilfs_dat_commit_entry(dat, req);
 149}
 150
 151int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)
 152{
 153        struct nilfs_dat_entry *entry;
 154        sector_t blocknr;
 155        void *kaddr;
 156        int ret;
 157
 158        ret = nilfs_dat_prepare_entry(dat, req, 0);
 159        if (ret < 0) {
 160                WARN_ON(ret == -ENOENT);
 161                return ret;
 162        }
 163
 164        kaddr = kmap_atomic(req->pr_entry_bh->b_page);
 165        entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
 166                                             req->pr_entry_bh, kaddr);
 167        blocknr = le64_to_cpu(entry->de_blocknr);
 168        kunmap_atomic(kaddr);
 169
 170        if (blocknr == 0) {
 171                ret = nilfs_palloc_prepare_free_entry(dat, req);
 172                if (ret < 0) {
 173                        nilfs_dat_abort_entry(dat, req);
 174                        return ret;
 175                }
 176        }
 177
 178        return 0;
 179}
 180
 181void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req,
 182                          int dead)
 183{
 184        struct nilfs_dat_entry *entry;
 185        __u64 start, end;
 186        sector_t blocknr;
 187        void *kaddr;
 188
 189        kaddr = kmap_atomic(req->pr_entry_bh->b_page);
 190        entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
 191                                             req->pr_entry_bh, kaddr);
 192        end = start = le64_to_cpu(entry->de_start);
 193        if (!dead) {
 194                end = nilfs_mdt_cno(dat);
 195                WARN_ON(start > end);
 196        }
 197        entry->de_end = cpu_to_le64(end);
 198        blocknr = le64_to_cpu(entry->de_blocknr);
 199        kunmap_atomic(kaddr);
 200
 201        if (blocknr == 0)
 202                nilfs_dat_commit_free(dat, req);
 203        else
 204                nilfs_dat_commit_entry(dat, req);
 205}
 206
 207void nilfs_dat_abort_end(struct inode *dat, struct nilfs_palloc_req *req)
 208{
 209        struct nilfs_dat_entry *entry;
 210        __u64 start;
 211        sector_t blocknr;
 212        void *kaddr;
 213
 214        kaddr = kmap_atomic(req->pr_entry_bh->b_page);
 215        entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
 216                                             req->pr_entry_bh, kaddr);
 217        start = le64_to_cpu(entry->de_start);
 218        blocknr = le64_to_cpu(entry->de_blocknr);
 219        kunmap_atomic(kaddr);
 220
 221        if (start == nilfs_mdt_cno(dat) && blocknr == 0)
 222                nilfs_palloc_abort_free_entry(dat, req);
 223        nilfs_dat_abort_entry(dat, req);
 224}
 225
 226int nilfs_dat_prepare_update(struct inode *dat,
 227                             struct nilfs_palloc_req *oldreq,
 228                             struct nilfs_palloc_req *newreq)
 229{
 230        int ret;
 231
 232        ret = nilfs_dat_prepare_end(dat, oldreq);
 233        if (!ret) {
 234                ret = nilfs_dat_prepare_alloc(dat, newreq);
 235                if (ret < 0)
 236                        nilfs_dat_abort_end(dat, oldreq);
 237        }
 238        return ret;
 239}
 240
 241void nilfs_dat_commit_update(struct inode *dat,
 242                             struct nilfs_palloc_req *oldreq,
 243                             struct nilfs_palloc_req *newreq, int dead)
 244{
 245        nilfs_dat_commit_end(dat, oldreq, dead);
 246        nilfs_dat_commit_alloc(dat, newreq);
 247}
 248
 249void nilfs_dat_abort_update(struct inode *dat,
 250                            struct nilfs_palloc_req *oldreq,
 251                            struct nilfs_palloc_req *newreq)
 252{
 253        nilfs_dat_abort_end(dat, oldreq);
 254        nilfs_dat_abort_alloc(dat, newreq);
 255}
 256
 257/**
 258 * nilfs_dat_mark_dirty -
 259 * @dat: DAT file inode
 260 * @vblocknr: virtual block number
 261 *
 262 * Description:
 263 *
 264 * Return Value: On success, 0 is returned. On error, one of the following
 265 * negative error codes is returned.
 266 *
 267 * %-EIO - I/O error.
 268 *
 269 * %-ENOMEM - Insufficient amount of memory available.
 270 */
 271int nilfs_dat_mark_dirty(struct inode *dat, __u64 vblocknr)
 272{
 273        struct nilfs_palloc_req req;
 274        int ret;
 275
 276        req.pr_entry_nr = vblocknr;
 277        ret = nilfs_dat_prepare_entry(dat, &req, 0);
 278        if (ret == 0)
 279                nilfs_dat_commit_entry(dat, &req);
 280        return ret;
 281}
 282
 283/**
 284 * nilfs_dat_freev - free virtual block numbers
 285 * @dat: DAT file inode
 286 * @vblocknrs: array of virtual block numbers
 287 * @nitems: number of virtual block numbers
 288 *
 289 * Description: nilfs_dat_freev() frees the virtual block numbers specified by
 290 * @vblocknrs and @nitems.
 291 *
 292 * Return Value: On success, 0 is returned. On error, one of the following
 293 * negative error codes is returned.
 294 *
 295 * %-EIO - I/O error.
 296 *
 297 * %-ENOMEM - Insufficient amount of memory available.
 298 *
 299 * %-ENOENT - The virtual block number have not been allocated.
 300 */
 301int nilfs_dat_freev(struct inode *dat, __u64 *vblocknrs, size_t nitems)
 302{
 303        return nilfs_palloc_freev(dat, vblocknrs, nitems);
 304}
 305
 306/**
 307 * nilfs_dat_move - change a block number
 308 * @dat: DAT file inode
 309 * @vblocknr: virtual block number
 310 * @blocknr: block number
 311 *
 312 * Description: nilfs_dat_move() changes the block number associated with
 313 * @vblocknr to @blocknr.
 314 *
 315 * Return Value: On success, 0 is returned. On error, one of the following
 316 * negative error codes is returned.
 317 *
 318 * %-EIO - I/O error.
 319 *
 320 * %-ENOMEM - Insufficient amount of memory available.
 321 */
 322int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
 323{
 324        struct buffer_head *entry_bh;
 325        struct nilfs_dat_entry *entry;
 326        void *kaddr;
 327        int ret;
 328
 329        ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
 330        if (ret < 0)
 331                return ret;
 332
 333        /*
 334         * The given disk block number (blocknr) is not yet written to
 335         * the device at this point.
 336         *
 337         * To prevent nilfs_dat_translate() from returning the
 338         * uncommitted block number, this makes a copy of the entry
 339         * buffer and redirects nilfs_dat_translate() to the copy.
 340         */
 341        if (!buffer_nilfs_redirected(entry_bh)) {
 342                ret = nilfs_mdt_freeze_buffer(dat, entry_bh);
 343                if (ret) {
 344                        brelse(entry_bh);
 345                        return ret;
 346                }
 347        }
 348
 349        kaddr = kmap_atomic(entry_bh->b_page);
 350        entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
 351        if (unlikely(entry->de_blocknr == cpu_to_le64(0))) {
 352                nilfs_msg(dat->i_sb, KERN_CRIT,
 353                          "%s: invalid vblocknr = %llu, [%llu, %llu)",
 354                          __func__, (unsigned long long)vblocknr,
 355                          (unsigned long long)le64_to_cpu(entry->de_start),
 356                          (unsigned long long)le64_to_cpu(entry->de_end));
 357                kunmap_atomic(kaddr);
 358                brelse(entry_bh);
 359                return -EINVAL;
 360        }
 361        WARN_ON(blocknr == 0);
 362        entry->de_blocknr = cpu_to_le64(blocknr);
 363        kunmap_atomic(kaddr);
 364
 365        mark_buffer_dirty(entry_bh);
 366        nilfs_mdt_mark_dirty(dat);
 367
 368        brelse(entry_bh);
 369
 370        return 0;
 371}
 372
 373/**
 374 * nilfs_dat_translate - translate a virtual block number to a block number
 375 * @dat: DAT file inode
 376 * @vblocknr: virtual block number
 377 * @blocknrp: pointer to a block number
 378 *
 379 * Description: nilfs_dat_translate() maps the virtual block number @vblocknr
 380 * to the corresponding block number.
 381 *
 382 * Return Value: On success, 0 is returned and the block number associated
 383 * with @vblocknr is stored in the place pointed by @blocknrp. On error, one
 384 * of the following negative error codes is returned.
 385 *
 386 * %-EIO - I/O error.
 387 *
 388 * %-ENOMEM - Insufficient amount of memory available.
 389 *
 390 * %-ENOENT - A block number associated with @vblocknr does not exist.
 391 */
 392int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
 393{
 394        struct buffer_head *entry_bh, *bh;
 395        struct nilfs_dat_entry *entry;
 396        sector_t blocknr;
 397        void *kaddr;
 398        int ret;
 399
 400        ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
 401        if (ret < 0)
 402                return ret;
 403
 404        if (!nilfs_doing_gc() && buffer_nilfs_redirected(entry_bh)) {
 405                bh = nilfs_mdt_get_frozen_buffer(dat, entry_bh);
 406                if (bh) {
 407                        WARN_ON(!buffer_uptodate(bh));
 408                        brelse(entry_bh);
 409                        entry_bh = bh;
 410                }
 411        }
 412
 413        kaddr = kmap_atomic(entry_bh->b_page);
 414        entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
 415        blocknr = le64_to_cpu(entry->de_blocknr);
 416        if (blocknr == 0) {
 417                ret = -ENOENT;
 418                goto out;
 419        }
 420        *blocknrp = blocknr;
 421
 422 out:
 423        kunmap_atomic(kaddr);
 424        brelse(entry_bh);
 425        return ret;
 426}
 427
 428ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned int visz,
 429                            size_t nvi)
 430{
 431        struct buffer_head *entry_bh;
 432        struct nilfs_dat_entry *entry;
 433        struct nilfs_vinfo *vinfo = buf;
 434        __u64 first, last;
 435        void *kaddr;
 436        unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block;
 437        int i, j, n, ret;
 438
 439        for (i = 0; i < nvi; i += n) {
 440                ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr,
 441                                                   0, &entry_bh);
 442                if (ret < 0)
 443                        return ret;
 444                kaddr = kmap_atomic(entry_bh->b_page);
 445                /* last virtual block number in this block */
 446                first = vinfo->vi_vblocknr;
 447                do_div(first, entries_per_block);
 448                first *= entries_per_block;
 449                last = first + entries_per_block - 1;
 450                for (j = i, n = 0;
 451                     j < nvi && vinfo->vi_vblocknr >= first &&
 452                             vinfo->vi_vblocknr <= last;
 453                     j++, n++, vinfo = (void *)vinfo + visz) {
 454                        entry = nilfs_palloc_block_get_entry(
 455                                dat, vinfo->vi_vblocknr, entry_bh, kaddr);
 456                        vinfo->vi_start = le64_to_cpu(entry->de_start);
 457                        vinfo->vi_end = le64_to_cpu(entry->de_end);
 458                        vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr);
 459                }
 460                kunmap_atomic(kaddr);
 461                brelse(entry_bh);
 462        }
 463
 464        return nvi;
 465}
 466
 467/**
 468 * nilfs_dat_read - read or get dat inode
 469 * @sb: super block instance
 470 * @entry_size: size of a dat entry
 471 * @raw_inode: on-disk dat inode
 472 * @inodep: buffer to store the inode
 473 */
 474int nilfs_dat_read(struct super_block *sb, size_t entry_size,
 475                   struct nilfs_inode *raw_inode, struct inode **inodep)
 476{
 477        static struct lock_class_key dat_lock_key;
 478        struct inode *dat;
 479        struct nilfs_dat_info *di;
 480        int err;
 481
 482        if (entry_size > sb->s_blocksize) {
 483                nilfs_msg(sb, KERN_ERR, "too large DAT entry size: %zu bytes",
 484                          entry_size);
 485                return -EINVAL;
 486        } else if (entry_size < NILFS_MIN_DAT_ENTRY_SIZE) {
 487                nilfs_msg(sb, KERN_ERR, "too small DAT entry size: %zu bytes",
 488                          entry_size);
 489                return -EINVAL;
 490        }
 491
 492        dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO);
 493        if (unlikely(!dat))
 494                return -ENOMEM;
 495        if (!(dat->i_state & I_NEW))
 496                goto out;
 497
 498        err = nilfs_mdt_init(dat, NILFS_MDT_GFP, sizeof(*di));
 499        if (err)
 500                goto failed;
 501
 502        err = nilfs_palloc_init_blockgroup(dat, entry_size);
 503        if (err)
 504                goto failed;
 505
 506        di = NILFS_DAT_I(dat);
 507        lockdep_set_class(&di->mi.mi_sem, &dat_lock_key);
 508        nilfs_palloc_setup_cache(dat, &di->palloc_cache);
 509        nilfs_mdt_setup_shadow_map(dat, &di->shadow);
 510
 511        err = nilfs_read_inode_common(dat, raw_inode);
 512        if (err)
 513                goto failed;
 514
 515        unlock_new_inode(dat);
 516 out:
 517        *inodep = dat;
 518        return 0;
 519 failed:
 520        iget_failed(dat);
 521        return err;
 522}
 523