nilfs really shouldn't slap struct dentry on stack...
[safe/jmp/linux-2.6] / fs / nilfs2 / direct.c
index e3ec248..236753d 100644 (file)
@@ -25,6 +25,7 @@
 #include "page.h"
 #include "direct.h"
 #include "alloc.h"
+#include "dat.h"
 
 static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct)
 {
@@ -50,11 +51,11 @@ static int nilfs_direct_lookup(const struct nilfs_bmap *bmap,
        struct nilfs_direct *direct;
        __u64 ptr;
 
-       direct = (struct nilfs_direct *)bmap;
-       if ((key > NILFS_DIRECT_KEY_MAX) ||
-           (level != 1) ||     /* XXX: use macro for level 1 */
-           ((ptr = nilfs_direct_get_ptr(direct, key)) ==
-            NILFS_BMAP_INVALID_PTR))
+       direct = (struct nilfs_direct *)bmap;  /* XXX: use macro for level 1 */
+       if (key > NILFS_DIRECT_KEY_MAX || level != 1)
+               return -ENOENT;
+       ptr = nilfs_direct_get_ptr(direct, key);
+       if (ptr == NILFS_BMAP_INVALID_PTR)
                return -ENOENT;
 
        if (ptrp != NULL)
@@ -62,6 +63,48 @@ static int nilfs_direct_lookup(const struct nilfs_bmap *bmap,
        return 0;
 }
 
+static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap,
+                                     __u64 key, __u64 *ptrp,
+                                     unsigned maxblocks)
+{
+       struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
+       struct inode *dat = NULL;
+       __u64 ptr, ptr2;
+       sector_t blocknr;
+       int ret, cnt;
+
+       if (key > NILFS_DIRECT_KEY_MAX)
+               return -ENOENT;
+       ptr = nilfs_direct_get_ptr(direct, key);
+       if (ptr == NILFS_BMAP_INVALID_PTR)
+               return -ENOENT;
+
+       if (NILFS_BMAP_USE_VBN(bmap)) {
+               dat = nilfs_bmap_get_dat(bmap);
+               ret = nilfs_dat_translate(dat, ptr, &blocknr);
+               if (ret < 0)
+                       return ret;
+               ptr = blocknr;
+       }
+
+       maxblocks = min_t(unsigned, maxblocks, NILFS_DIRECT_KEY_MAX - key + 1);
+       for (cnt = 1; cnt < maxblocks &&
+                    (ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) !=
+                    NILFS_BMAP_INVALID_PTR;
+            cnt++) {
+               if (dat) {
+                       ret = nilfs_dat_translate(dat, ptr2, &blocknr);
+                       if (ret < 0)
+                               return ret;
+                       ptr2 = blocknr;
+               }
+               if (ptr2 != ptr + cnt)
+                       break;
+       }
+       *ptrp = ptr;
+       return cnt;
+}
+
 static __u64
 nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key)
 {
@@ -83,116 +126,64 @@ static void nilfs_direct_set_target_v(struct nilfs_direct *direct,
        direct->d_bmap.b_last_allocated_ptr = ptr;
 }
 
-static int nilfs_direct_prepare_insert(struct nilfs_direct *direct,
-                                      __u64 key,
-                                      union nilfs_bmap_ptr_req *req,
-                                      struct nilfs_bmap_stats *stats)
-{
-       int ret;
-
-       if (direct->d_ops->dop_find_target != NULL)
-               req->bpr_ptr = direct->d_ops->dop_find_target(direct, key);
-       ret = direct->d_bmap.b_pops->bpop_prepare_alloc_ptr(&direct->d_bmap,
-                                                              req);
-       if (ret < 0)
-               return ret;
-
-       stats->bs_nblocks = 1;
-       return 0;
-}
-
-static void nilfs_direct_commit_insert(struct nilfs_direct *direct,
-                                      union nilfs_bmap_ptr_req *req,
-                                      __u64 key, __u64 ptr)
-{
-       struct buffer_head *bh;
-
-       /* ptr must be a pointer to a buffer head. */
-       bh = (struct buffer_head *)((unsigned long)ptr);
-       set_buffer_nilfs_volatile(bh);
-
-       if (direct->d_bmap.b_pops->bpop_commit_alloc_ptr != NULL)
-               direct->d_bmap.b_pops->bpop_commit_alloc_ptr(
-                       &direct->d_bmap, req);
-       nilfs_direct_set_ptr(direct, key, req->bpr_ptr);
-
-       if (!nilfs_bmap_dirty(&direct->d_bmap))
-               nilfs_bmap_set_dirty(&direct->d_bmap);
-
-       if (direct->d_ops->dop_set_target != NULL)
-               direct->d_ops->dop_set_target(direct, key, req->bpr_ptr);
-}
-
 static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
 {
-       struct nilfs_direct *direct;
+       struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
        union nilfs_bmap_ptr_req req;
-       struct nilfs_bmap_stats stats;
+       struct inode *dat = NULL;
+       struct buffer_head *bh;
        int ret;
 
-       direct = (struct nilfs_direct *)bmap;
        if (key > NILFS_DIRECT_KEY_MAX)
                return -ENOENT;
        if (nilfs_direct_get_ptr(direct, key) != NILFS_BMAP_INVALID_PTR)
                return -EEXIST;
 
-       ret = nilfs_direct_prepare_insert(direct, key, &req, &stats);
-       if (ret < 0)
-               return ret;
-       nilfs_direct_commit_insert(direct, &req, key, ptr);
-       nilfs_bmap_add_blocks(bmap, stats.bs_nblocks);
-
-       return 0;
-}
+       if (NILFS_BMAP_USE_VBN(bmap)) {
+               req.bpr_ptr = nilfs_direct_find_target_v(direct, key);
+               dat = nilfs_bmap_get_dat(bmap);
+       }
+       ret = nilfs_bmap_prepare_alloc_ptr(bmap, &req, dat);
+       if (!ret) {
+               /* ptr must be a pointer to a buffer head. */
+               bh = (struct buffer_head *)((unsigned long)ptr);
+               set_buffer_nilfs_volatile(bh);
 
-static int nilfs_direct_prepare_delete(struct nilfs_direct *direct,
-                                      union nilfs_bmap_ptr_req *req,
-                                      __u64 key,
-                                      struct nilfs_bmap_stats *stats)
-{
-       int ret;
+               nilfs_bmap_commit_alloc_ptr(bmap, &req, dat);
+               nilfs_direct_set_ptr(direct, key, req.bpr_ptr);
 
-       if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) {
-               req->bpr_ptr = nilfs_direct_get_ptr(direct, key);
-               ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr(
-                       &direct->d_bmap, req);
-               if (ret < 0)
-                       return ret;
-       }
+               if (!nilfs_bmap_dirty(bmap))
+                       nilfs_bmap_set_dirty(bmap);
 
-       stats->bs_nblocks = 1;
-       return 0;
-}
+               if (NILFS_BMAP_USE_VBN(bmap))
+                       nilfs_direct_set_target_v(direct, key, req.bpr_ptr);
 
-static void nilfs_direct_commit_delete(struct nilfs_direct *direct,
-                                      union nilfs_bmap_ptr_req *req,
-                                      __u64 key)
-{
-       if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL)
-               direct->d_bmap.b_pops->bpop_commit_end_ptr(
-                       &direct->d_bmap, req);
-       nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR);
+               nilfs_bmap_add_blocks(bmap, 1);
+       }
+       return ret;
 }
 
 static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key)
 {
-       struct nilfs_direct *direct;
+       struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
        union nilfs_bmap_ptr_req req;
-       struct nilfs_bmap_stats stats;
+       struct inode *dat;
        int ret;
 
-       direct = (struct nilfs_direct *)bmap;
-       if ((key > NILFS_DIRECT_KEY_MAX) ||
+       if (key > NILFS_DIRECT_KEY_MAX ||
            nilfs_direct_get_ptr(direct, key) == NILFS_BMAP_INVALID_PTR)
                return -ENOENT;
 
-       ret = nilfs_direct_prepare_delete(direct, &req, key, &stats);
-       if (ret < 0)
-               return ret;
-       nilfs_direct_commit_delete(direct, &req, key);
-       nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks);
+       dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL;
+       req.bpr_ptr = nilfs_direct_get_ptr(direct, key);
 
-       return 0;
+       ret = nilfs_bmap_prepare_end_ptr(bmap, &req, dat);
+       if (!ret) {
+               nilfs_bmap_commit_end_ptr(bmap, &req, dat);
+               nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR);
+               nilfs_bmap_sub_blocks(bmap, 1);
+       }
+       return ret;
 }
 
 static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp)
@@ -210,7 +201,6 @@ static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp)
        if (lastkey == NILFS_DIRECT_KEY_MAX + 1)
                return -ENOENT;
 
-       BUG_ON(keyp == NULL);
        *keyp = lastkey;
 
        return 0;
@@ -245,8 +235,7 @@ static int nilfs_direct_gather_data(struct nilfs_bmap *bmap,
 }
 
 int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
-                                   __u64 key, __u64 *keys, __u64 *ptrs,
-                                   int n, __u64 low, __u64 high)
+                                   __u64 key, __u64 *keys, __u64 *ptrs, int n)
 {
        struct nilfs_direct *direct;
        __le64 *dptrs;
@@ -276,69 +265,60 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
                        dptrs[i] = NILFS_BMAP_INVALID_PTR;
        }
 
-       nilfs_direct_init(bmap, low, high);
-
+       nilfs_direct_init(bmap);
        return 0;
 }
 
-static int nilfs_direct_propagate_v(struct nilfs_direct *direct,
-                                   struct buffer_head *bh)
+static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
+                                 struct buffer_head *bh)
 {
-       union nilfs_bmap_ptr_req oldreq, newreq;
+       struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
+       struct nilfs_palloc_req oldreq, newreq;
+       struct inode *dat;
        __u64 key;
        __u64 ptr;
        int ret;
 
-       key = nilfs_bmap_data_get_key(&direct->d_bmap, bh);
+       if (!NILFS_BMAP_USE_VBN(bmap))
+               return 0;
+
+       dat = nilfs_bmap_get_dat(bmap);
+       key = nilfs_bmap_data_get_key(bmap, bh);
        ptr = nilfs_direct_get_ptr(direct, key);
        if (!buffer_nilfs_volatile(bh)) {
-               oldreq.bpr_ptr = ptr;
-               newreq.bpr_ptr = ptr;
-               ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq,
-                                               &newreq);
+               oldreq.pr_entry_nr = ptr;
+               newreq.pr_entry_nr = ptr;
+               ret = nilfs_dat_prepare_update(dat, &oldreq, &newreq);
                if (ret < 0)
                        return ret;
-               nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq);
+               nilfs_dat_commit_update(dat, &oldreq, &newreq,
+                                       bmap->b_ptr_type == NILFS_BMAP_PTR_VS);
                set_buffer_nilfs_volatile(bh);
-               nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr);
+               nilfs_direct_set_ptr(direct, key, newreq.pr_entry_nr);
        } else
-               ret = nilfs_bmap_mark_dirty(&direct->d_bmap, ptr);
+               ret = nilfs_dat_mark_dirty(dat, ptr);
 
        return ret;
 }
 
-static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
-                                 struct buffer_head *bh)
-{
-       struct nilfs_direct *direct;
-
-       direct = (struct nilfs_direct *)bmap;
-       return (direct->d_ops->dop_propagate != NULL) ?
-               direct->d_ops->dop_propagate(direct, bh) :
-               0;
-}
-
 static int nilfs_direct_assign_v(struct nilfs_direct *direct,
                                 __u64 key, __u64 ptr,
                                 struct buffer_head **bh,
                                 sector_t blocknr,
                                 union nilfs_binfo *binfo)
 {
+       struct inode *dat = nilfs_bmap_get_dat(&direct->d_bmap);
        union nilfs_bmap_ptr_req req;
        int ret;
 
        req.bpr_ptr = ptr;
-       ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr(
-               &direct->d_bmap, &req);
-       if (ret < 0)
-               return ret;
-       direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap,
-                                                    &req, blocknr);
-
-       binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr);
-       binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
-
-       return 0;
+       ret = nilfs_dat_prepare_start(dat, &req.bpr_req);
+       if (!ret) {
+               nilfs_dat_commit_start(dat, &req.bpr_req, blocknr);
+               binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr);
+               binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
+       }
+       return ret;
 }
 
 static int nilfs_direct_assign_p(struct nilfs_direct *direct,
@@ -366,16 +346,26 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap,
 
        direct = (struct nilfs_direct *)bmap;
        key = nilfs_bmap_data_get_key(bmap, *bh);
-       BUG_ON(key > NILFS_DIRECT_KEY_MAX);
+       if (unlikely(key > NILFS_DIRECT_KEY_MAX)) {
+               printk(KERN_CRIT "%s: invalid key: %llu\n", __func__,
+                      (unsigned long long)key);
+               return -EINVAL;
+       }
        ptr = nilfs_direct_get_ptr(direct, key);
-       BUG_ON(ptr == NILFS_BMAP_INVALID_PTR);
+       if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) {
+               printk(KERN_CRIT "%s: invalid pointer: %llu\n", __func__,
+                      (unsigned long long)ptr);
+               return -EINVAL;
+       }
 
-       return direct->d_ops->dop_assign(direct, key, ptr, bh,
-                                        blocknr, binfo);
+       return NILFS_BMAP_USE_VBN(bmap) ?
+               nilfs_direct_assign_v(direct, key, ptr, bh, blocknr, binfo) :
+               nilfs_direct_assign_p(direct, key, ptr, bh, blocknr, binfo);
 }
 
 static const struct nilfs_bmap_operations nilfs_direct_ops = {
        .bop_lookup             =       nilfs_direct_lookup,
+       .bop_lookup_contig      =       nilfs_direct_lookup_contig,
        .bop_insert             =       nilfs_direct_insert,
        .bop_delete             =       nilfs_direct_delete,
        .bop_clear              =       NULL,
@@ -394,36 +384,8 @@ static const struct nilfs_bmap_operations nilfs_direct_ops = {
 };
 
 
-static const struct nilfs_direct_operations nilfs_direct_ops_v = {
-       .dop_find_target        =       nilfs_direct_find_target_v,
-       .dop_set_target         =       nilfs_direct_set_target_v,
-       .dop_propagate          =       nilfs_direct_propagate_v,
-       .dop_assign             =       nilfs_direct_assign_v,
-};
-
-static const struct nilfs_direct_operations nilfs_direct_ops_p = {
-       .dop_find_target        =       NULL,
-       .dop_set_target         =       NULL,
-       .dop_propagate          =       NULL,
-       .dop_assign             =       nilfs_direct_assign_p,
-};
-
-int nilfs_direct_init(struct nilfs_bmap *bmap, __u64 low, __u64 high)
+int nilfs_direct_init(struct nilfs_bmap *bmap)
 {
-       struct nilfs_direct *direct;
-
-       direct = (struct nilfs_direct *)bmap;
        bmap->b_ops = &nilfs_direct_ops;
-       bmap->b_low = low;
-       bmap->b_high = high;
-       switch (bmap->b_inode->i_ino) {
-       case NILFS_DAT_INO:
-               direct->d_ops = &nilfs_direct_ops_p;
-               break;
-       default:
-               direct->d_ops = &nilfs_direct_ops_v;
-               break;
-       }
-
        return 0;
 }