linux/fs/nilfs2/btnode.c
<<
>>
Prefs
   1/*
   2 * btnode.c - NILFS B-tree node cache
   3 *
   4 * Copyright (C) 2005-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 * Originally written by Seiji Kihara.
  17 * Fully revised by Ryusuke Konishi for stabilization and simplification.
  18 *
  19 */
  20
  21#include <linux/types.h>
  22#include <linux/buffer_head.h>
  23#include <linux/mm.h>
  24#include <linux/backing-dev.h>
  25#include <linux/gfp.h>
  26#include "nilfs.h"
  27#include "mdt.h"
  28#include "dat.h"
  29#include "page.h"
  30#include "btnode.h"
  31
  32void nilfs_btnode_cache_clear(struct address_space *btnc)
  33{
  34        invalidate_mapping_pages(btnc, 0, -1);
  35        truncate_inode_pages(btnc, 0);
  36}
  37
  38struct buffer_head *
  39nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)
  40{
  41        struct inode *inode = NILFS_BTNC_I(btnc);
  42        struct buffer_head *bh;
  43
  44        bh = nilfs_grab_buffer(inode, btnc, blocknr, BIT(BH_NILFS_Node));
  45        if (unlikely(!bh))
  46                return NULL;
  47
  48        if (unlikely(buffer_mapped(bh) || buffer_uptodate(bh) ||
  49                     buffer_dirty(bh))) {
  50                brelse(bh);
  51                BUG();
  52        }
  53        memset(bh->b_data, 0, 1 << inode->i_blkbits);
  54        bh->b_bdev = inode->i_sb->s_bdev;
  55        bh->b_blocknr = blocknr;
  56        set_buffer_mapped(bh);
  57        set_buffer_uptodate(bh);
  58
  59        unlock_page(bh->b_page);
  60        put_page(bh->b_page);
  61        return bh;
  62}
  63
  64int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
  65                              sector_t pblocknr, int mode, int mode_flags,
  66                              struct buffer_head **pbh, sector_t *submit_ptr)
  67{
  68        struct buffer_head *bh;
  69        struct inode *inode = NILFS_BTNC_I(btnc);
  70        struct page *page;
  71        int err;
  72
  73        bh = nilfs_grab_buffer(inode, btnc, blocknr, BIT(BH_NILFS_Node));
  74        if (unlikely(!bh))
  75                return -ENOMEM;
  76
  77        err = -EEXIST; /* internal code */
  78        page = bh->b_page;
  79
  80        if (buffer_uptodate(bh) || buffer_dirty(bh))
  81                goto found;
  82
  83        if (pblocknr == 0) {
  84                pblocknr = blocknr;
  85                if (inode->i_ino != NILFS_DAT_INO) {
  86                        struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
  87
  88                        /* blocknr is a virtual block number */
  89                        err = nilfs_dat_translate(nilfs->ns_dat, blocknr,
  90                                                  &pblocknr);
  91                        if (unlikely(err)) {
  92                                brelse(bh);
  93                                goto out_locked;
  94                        }
  95                }
  96        }
  97
  98        if (mode_flags & REQ_RAHEAD) {
  99                if (pblocknr != *submit_ptr + 1 || !trylock_buffer(bh)) {
 100                        err = -EBUSY; /* internal code */
 101                        brelse(bh);
 102                        goto out_locked;
 103                }
 104        } else { /* mode == READ */
 105                lock_buffer(bh);
 106        }
 107        if (buffer_uptodate(bh)) {
 108                unlock_buffer(bh);
 109                err = -EEXIST; /* internal code */
 110                goto found;
 111        }
 112        set_buffer_mapped(bh);
 113        bh->b_bdev = inode->i_sb->s_bdev;
 114        bh->b_blocknr = pblocknr; /* set block address for read */
 115        bh->b_end_io = end_buffer_read_sync;
 116        get_bh(bh);
 117        submit_bh(mode, mode_flags, bh);
 118        bh->b_blocknr = blocknr; /* set back to the given block address */
 119        *submit_ptr = pblocknr;
 120        err = 0;
 121found:
 122        *pbh = bh;
 123
 124out_locked:
 125        unlock_page(page);
 126        put_page(page);
 127        return err;
 128}
 129
 130/**
 131 * nilfs_btnode_delete - delete B-tree node buffer
 132 * @bh: buffer to be deleted
 133 *
 134 * nilfs_btnode_delete() invalidates the specified buffer and delete the page
 135 * including the buffer if the page gets unbusy.
 136 */
 137void nilfs_btnode_delete(struct buffer_head *bh)
 138{
 139        struct address_space *mapping;
 140        struct page *page = bh->b_page;
 141        pgoff_t index = page_index(page);
 142        int still_dirty;
 143
 144        get_page(page);
 145        lock_page(page);
 146        wait_on_page_writeback(page);
 147
 148        nilfs_forget_buffer(bh);
 149        still_dirty = PageDirty(page);
 150        mapping = page->mapping;
 151        unlock_page(page);
 152        put_page(page);
 153
 154        if (!still_dirty && mapping)
 155                invalidate_inode_pages2_range(mapping, index, index);
 156}
 157
 158/**
 159 * nilfs_btnode_prepare_change_key
 160 *  prepare to move contents of the block for old key to one of new key.
 161 *  the old buffer will not be removed, but might be reused for new buffer.
 162 *  it might return -ENOMEM because of memory allocation errors,
 163 *  and might return -EIO because of disk read errors.
 164 */
 165int nilfs_btnode_prepare_change_key(struct address_space *btnc,
 166                                    struct nilfs_btnode_chkey_ctxt *ctxt)
 167{
 168        struct buffer_head *obh, *nbh;
 169        struct inode *inode = NILFS_BTNC_I(btnc);
 170        __u64 oldkey = ctxt->oldkey, newkey = ctxt->newkey;
 171        int err;
 172
 173        if (oldkey == newkey)
 174                return 0;
 175
 176        obh = ctxt->bh;
 177        ctxt->newbh = NULL;
 178
 179        if (inode->i_blkbits == PAGE_SHIFT) {
 180                lock_page(obh->b_page);
 181                /*
 182                 * We cannot call radix_tree_preload for the kernels older
 183                 * than 2.6.23, because it is not exported for modules.
 184                 */
 185retry:
 186                err = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
 187                if (err)
 188                        goto failed_unlock;
 189                /* BUG_ON(oldkey != obh->b_page->index); */
 190                if (unlikely(oldkey != obh->b_page->index))
 191                        NILFS_PAGE_BUG(obh->b_page,
 192                                       "invalid oldkey %lld (newkey=%lld)",
 193                                       (unsigned long long)oldkey,
 194                                       (unsigned long long)newkey);
 195
 196                spin_lock_irq(&btnc->tree_lock);
 197                err = radix_tree_insert(&btnc->page_tree, newkey, obh->b_page);
 198                spin_unlock_irq(&btnc->tree_lock);
 199                /*
 200                 * Note: page->index will not change to newkey until
 201                 * nilfs_btnode_commit_change_key() will be called.
 202                 * To protect the page in intermediate state, the page lock
 203                 * is held.
 204                 */
 205                radix_tree_preload_end();
 206                if (!err)
 207                        return 0;
 208                else if (err != -EEXIST)
 209                        goto failed_unlock;
 210
 211                err = invalidate_inode_pages2_range(btnc, newkey, newkey);
 212                if (!err)
 213                        goto retry;
 214                /* fallback to copy mode */
 215                unlock_page(obh->b_page);
 216        }
 217
 218        nbh = nilfs_btnode_create_block(btnc, newkey);
 219        if (!nbh)
 220                return -ENOMEM;
 221
 222        BUG_ON(nbh == obh);
 223        ctxt->newbh = nbh;
 224        return 0;
 225
 226 failed_unlock:
 227        unlock_page(obh->b_page);
 228        return err;
 229}
 230
 231/**
 232 * nilfs_btnode_commit_change_key
 233 *  commit the change_key operation prepared by prepare_change_key().
 234 */
 235void nilfs_btnode_commit_change_key(struct address_space *btnc,
 236                                    struct nilfs_btnode_chkey_ctxt *ctxt)
 237{
 238        struct buffer_head *obh = ctxt->bh, *nbh = ctxt->newbh;
 239        __u64 oldkey = ctxt->oldkey, newkey = ctxt->newkey;
 240        struct page *opage;
 241
 242        if (oldkey == newkey)
 243                return;
 244
 245        if (nbh == NULL) {      /* blocksize == pagesize */
 246                opage = obh->b_page;
 247                if (unlikely(oldkey != opage->index))
 248                        NILFS_PAGE_BUG(opage,
 249                                       "invalid oldkey %lld (newkey=%lld)",
 250                                       (unsigned long long)oldkey,
 251                                       (unsigned long long)newkey);
 252                mark_buffer_dirty(obh);
 253
 254                spin_lock_irq(&btnc->tree_lock);
 255                radix_tree_delete(&btnc->page_tree, oldkey);
 256                radix_tree_tag_set(&btnc->page_tree, newkey,
 257                                   PAGECACHE_TAG_DIRTY);
 258                spin_unlock_irq(&btnc->tree_lock);
 259
 260                opage->index = obh->b_blocknr = newkey;
 261                unlock_page(opage);
 262        } else {
 263                nilfs_copy_buffer(nbh, obh);
 264                mark_buffer_dirty(nbh);
 265
 266                nbh->b_blocknr = newkey;
 267                ctxt->bh = nbh;
 268                nilfs_btnode_delete(obh); /* will decrement bh->b_count */
 269        }
 270}
 271
 272/**
 273 * nilfs_btnode_abort_change_key
 274 *  abort the change_key operation prepared by prepare_change_key().
 275 */
 276void nilfs_btnode_abort_change_key(struct address_space *btnc,
 277                                   struct nilfs_btnode_chkey_ctxt *ctxt)
 278{
 279        struct buffer_head *nbh = ctxt->newbh;
 280        __u64 oldkey = ctxt->oldkey, newkey = ctxt->newkey;
 281
 282        if (oldkey == newkey)
 283                return;
 284
 285        if (nbh == NULL) {      /* blocksize == pagesize */
 286                spin_lock_irq(&btnc->tree_lock);
 287                radix_tree_delete(&btnc->page_tree, newkey);
 288                spin_unlock_irq(&btnc->tree_lock);
 289                unlock_page(ctxt->bh->b_page);
 290        } else
 291                brelse(nbh);
 292}
 293