~ubuntu-branches/ubuntu/lucid/linux-rt/lucid

« back to all changes in this revision

Viewing changes to fs/nilfs2/direct.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-08-05 23:00:52 UTC
  • Revision ID: james.westby@ubuntu.com-20090805230052-7xedvqcyk9dnnxb2
Tags: 2.6.31-1.1
New upstream release

Show diffs side-by-side

added added

removed removed

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