~ubuntu-branches/ubuntu/quantal/linux-lowlatency/quantal

« back to all changes in this revision

Viewing changes to ubuntu/aufs/wbr_policy.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-04kado7d1u2er2rl
Tags: 3.2.0-16.25
Add new lowlatency kernel flavour

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005-2011 Junjiro R. Okajima
 
3
 *
 
4
 * This program, aufs is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 */
 
18
 
 
19
/*
 
20
 * policies for selecting one among multiple writable branches
 
21
 */
 
22
 
 
23
#include <linux/statfs.h>
 
24
#include "aufs.h"
 
25
 
 
26
/* subset of cpup_attr() */
 
27
static noinline_for_stack
 
28
int au_cpdown_attr(struct path *h_path, struct dentry *h_src)
 
29
{
 
30
        int err, sbits;
 
31
        struct iattr ia;
 
32
        struct inode *h_isrc;
 
33
 
 
34
        h_isrc = h_src->d_inode;
 
35
        ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID;
 
36
        ia.ia_mode = h_isrc->i_mode;
 
37
        ia.ia_uid = h_isrc->i_uid;
 
38
        ia.ia_gid = h_isrc->i_gid;
 
39
        sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
 
40
        au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc);
 
41
        err = vfsub_sio_notify_change(h_path, &ia);
 
42
 
 
43
        /* is this nfs only? */
 
44
        if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) {
 
45
                ia.ia_valid = ATTR_FORCE | ATTR_MODE;
 
46
                ia.ia_mode = h_isrc->i_mode;
 
47
                err = vfsub_sio_notify_change(h_path, &ia);
 
48
        }
 
49
 
 
50
        return err;
 
51
}
 
52
 
 
53
#define AuCpdown_PARENT_OPQ     1
 
54
#define AuCpdown_WHED           (1 << 1)
 
55
#define AuCpdown_MADE_DIR       (1 << 2)
 
56
#define AuCpdown_DIROPQ         (1 << 3)
 
57
#define au_ftest_cpdown(flags, name)    ((flags) & AuCpdown_##name)
 
58
#define au_fset_cpdown(flags, name) \
 
59
        do { (flags) |= AuCpdown_##name; } while (0)
 
60
#define au_fclr_cpdown(flags, name) \
 
61
        do { (flags) &= ~AuCpdown_##name; } while (0)
 
62
 
 
63
struct au_cpdown_dir_args {
 
64
        struct dentry *parent;
 
65
        unsigned int flags;
 
66
};
 
67
 
 
68
static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst,
 
69
                             struct au_cpdown_dir_args *a)
 
70
{
 
71
        int err;
 
72
        struct dentry *opq_dentry;
 
73
 
 
74
        opq_dentry = au_diropq_create(dentry, bdst);
 
75
        err = PTR_ERR(opq_dentry);
 
76
        if (IS_ERR(opq_dentry))
 
77
                goto out;
 
78
        dput(opq_dentry);
 
79
        au_fset_cpdown(a->flags, DIROPQ);
 
80
 
 
81
out:
 
82
        return err;
 
83
}
 
84
 
 
85
static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent,
 
86
                            struct inode *dir, aufs_bindex_t bdst)
 
87
{
 
88
        int err;
 
89
        struct path h_path;
 
90
        struct au_branch *br;
 
91
 
 
92
        br = au_sbr(dentry->d_sb, bdst);
 
93
        h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
 
94
        err = PTR_ERR(h_path.dentry);
 
95
        if (IS_ERR(h_path.dentry))
 
96
                goto out;
 
97
 
 
98
        err = 0;
 
99
        if (h_path.dentry->d_inode) {
 
100
                h_path.mnt = br->br_mnt;
 
101
                err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path,
 
102
                                          dentry);
 
103
        }
 
104
        dput(h_path.dentry);
 
105
 
 
106
out:
 
107
        return err;
 
108
}
 
109
 
 
110
static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst,
 
111
                         struct dentry *h_parent, void *arg)
 
112
{
 
113
        int err, rerr;
 
114
        aufs_bindex_t bopq, bstart;
 
115
        struct path h_path;
 
116
        struct dentry *parent;
 
117
        struct inode *h_dir, *h_inode, *inode, *dir;
 
118
        struct au_cpdown_dir_args *args = arg;
 
119
 
 
120
        bstart = au_dbstart(dentry);
 
121
        /* dentry is di-locked */
 
122
        parent = dget_parent(dentry);
 
123
        dir = parent->d_inode;
 
124
        h_dir = h_parent->d_inode;
 
125
        AuDebugOn(h_dir != au_h_iptr(dir, bdst));
 
126
        IMustLock(h_dir);
 
127
 
 
128
        err = au_lkup_neg(dentry, bdst);
 
129
        if (unlikely(err < 0))
 
130
                goto out;
 
131
        h_path.dentry = au_h_dptr(dentry, bdst);
 
132
        h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst);
 
133
        err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path,
 
134
                              S_IRWXU | S_IRUGO | S_IXUGO);
 
135
        if (unlikely(err))
 
136
                goto out_put;
 
137
        au_fset_cpdown(args->flags, MADE_DIR);
 
138
 
 
139
        bopq = au_dbdiropq(dentry);
 
140
        au_fclr_cpdown(args->flags, WHED);
 
141
        au_fclr_cpdown(args->flags, DIROPQ);
 
142
        if (au_dbwh(dentry) == bdst)
 
143
                au_fset_cpdown(args->flags, WHED);
 
144
        if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst)
 
145
                au_fset_cpdown(args->flags, PARENT_OPQ);
 
146
        h_inode = h_path.dentry->d_inode;
 
147
        mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
 
148
        if (au_ftest_cpdown(args->flags, WHED)) {
 
149
                err = au_cpdown_dir_opq(dentry, bdst, args);
 
150
                if (unlikely(err)) {
 
151
                        mutex_unlock(&h_inode->i_mutex);
 
152
                        goto out_dir;
 
153
                }
 
154
        }
 
155
 
 
156
        err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart));
 
157
        mutex_unlock(&h_inode->i_mutex);
 
158
        if (unlikely(err))
 
159
                goto out_opq;
 
160
 
 
161
        if (au_ftest_cpdown(args->flags, WHED)) {
 
162
                err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst);
 
163
                if (unlikely(err))
 
164
                        goto out_opq;
 
165
        }
 
166
 
 
167
        inode = dentry->d_inode;
 
168
        if (au_ibend(inode) < bdst)
 
169
                au_set_ibend(inode, bdst);
 
170
        au_set_h_iptr(inode, bdst, au_igrab(h_inode),
 
171
                      au_hi_flags(inode, /*isdir*/1));
 
172
        goto out; /* success */
 
173
 
 
174
        /* revert */
 
175
out_opq:
 
176
        if (au_ftest_cpdown(args->flags, DIROPQ)) {
 
177
                mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
 
178
                rerr = au_diropq_remove(dentry, bdst);
 
179
                mutex_unlock(&h_inode->i_mutex);
 
180
                if (unlikely(rerr)) {
 
181
                        AuIOErr("failed removing diropq for %.*s b%d (%d)\n",
 
182
                                AuDLNPair(dentry), bdst, rerr);
 
183
                        err = -EIO;
 
184
                        goto out;
 
185
                }
 
186
        }
 
187
out_dir:
 
188
        if (au_ftest_cpdown(args->flags, MADE_DIR)) {
 
189
                rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
 
190
                if (unlikely(rerr)) {
 
191
                        AuIOErr("failed removing %.*s b%d (%d)\n",
 
192
                                AuDLNPair(dentry), bdst, rerr);
 
193
                        err = -EIO;
 
194
                }
 
195
        }
 
196
out_put:
 
197
        au_set_h_dptr(dentry, bdst, NULL);
 
198
        if (au_dbend(dentry) == bdst)
 
199
                au_update_dbend(dentry);
 
200
out:
 
201
        dput(parent);
 
202
        return err;
 
203
}
 
204
 
 
205
int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
 
206
{
 
207
        int err;
 
208
        struct au_cpdown_dir_args args = {
 
209
                .parent = dget_parent(dentry),
 
210
                .flags  = 0
 
211
        };
 
212
 
 
213
        err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args);
 
214
        dput(args.parent);
 
215
 
 
216
        return err;
 
217
}
 
218
 
 
219
/* ---------------------------------------------------------------------- */
 
220
 
 
221
/* policies for create */
 
222
 
 
223
static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
 
224
{
 
225
        int err, i, j, ndentry;
 
226
        aufs_bindex_t bopq;
 
227
        struct au_dcsub_pages dpages;
 
228
        struct au_dpage *dpage;
 
229
        struct dentry **dentries, *parent, *d;
 
230
 
 
231
        err = au_dpages_init(&dpages, GFP_NOFS);
 
232
        if (unlikely(err))
 
233
                goto out;
 
234
        parent = dget_parent(dentry);
 
235
        err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0);
 
236
        if (unlikely(err))
 
237
                goto out_free;
 
238
 
 
239
        err = bindex;
 
240
        for (i = 0; i < dpages.ndpage; i++) {
 
241
                dpage = dpages.dpages + i;
 
242
                dentries = dpage->dentries;
 
243
                ndentry = dpage->ndentry;
 
244
                for (j = 0; j < ndentry; j++) {
 
245
                        d = dentries[j];
 
246
                        di_read_lock_parent2(d, !AuLock_IR);
 
247
                        bopq = au_dbdiropq(d);
 
248
                        di_read_unlock(d, !AuLock_IR);
 
249
                        if (bopq >= 0 && bopq < err)
 
250
                                err = bopq;
 
251
                }
 
252
        }
 
253
 
 
254
out_free:
 
255
        dput(parent);
 
256
        au_dpages_free(&dpages);
 
257
out:
 
258
        return err;
 
259
}
 
260
 
 
261
static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex)
 
262
{
 
263
        for (; bindex >= 0; bindex--)
 
264
                if (!au_br_rdonly(au_sbr(sb, bindex)))
 
265
                        return bindex;
 
266
        return -EROFS;
 
267
}
 
268
 
 
269
/* top down parent */
 
270
static int au_wbr_create_tdp(struct dentry *dentry, int isdir __maybe_unused)
 
271
{
 
272
        int err;
 
273
        aufs_bindex_t bstart, bindex;
 
274
        struct super_block *sb;
 
275
        struct dentry *parent, *h_parent;
 
276
 
 
277
        sb = dentry->d_sb;
 
278
        bstart = au_dbstart(dentry);
 
279
        err = bstart;
 
280
        if (!au_br_rdonly(au_sbr(sb, bstart)))
 
281
                goto out;
 
282
 
 
283
        err = -EROFS;
 
284
        parent = dget_parent(dentry);
 
285
        for (bindex = au_dbstart(parent); bindex < bstart; bindex++) {
 
286
                h_parent = au_h_dptr(parent, bindex);
 
287
                if (!h_parent || !h_parent->d_inode)
 
288
                        continue;
 
289
 
 
290
                if (!au_br_rdonly(au_sbr(sb, bindex))) {
 
291
                        err = bindex;
 
292
                        break;
 
293
                }
 
294
        }
 
295
        dput(parent);
 
296
 
 
297
        /* bottom up here */
 
298
        if (unlikely(err < 0)) {
 
299
                err = au_wbr_bu(sb, bstart - 1);
 
300
                if (err >= 0)
 
301
                        err = au_wbr_nonopq(dentry, err);
 
302
        }
 
303
 
 
304
out:
 
305
        AuDbg("b%d\n", err);
 
306
        return err;
 
307
}
 
308
 
 
309
/* ---------------------------------------------------------------------- */
 
310
 
 
311
/* an exception for the policy other than tdp */
 
312
static int au_wbr_create_exp(struct dentry *dentry)
 
313
{
 
314
        int err;
 
315
        aufs_bindex_t bwh, bdiropq;
 
316
        struct dentry *parent;
 
317
 
 
318
        err = -1;
 
319
        bwh = au_dbwh(dentry);
 
320
        parent = dget_parent(dentry);
 
321
        bdiropq = au_dbdiropq(parent);
 
322
        if (bwh >= 0) {
 
323
                if (bdiropq >= 0)
 
324
                        err = min(bdiropq, bwh);
 
325
                else
 
326
                        err = bwh;
 
327
                AuDbg("%d\n", err);
 
328
        } else if (bdiropq >= 0) {
 
329
                err = bdiropq;
 
330
                AuDbg("%d\n", err);
 
331
        }
 
332
        dput(parent);
 
333
 
 
334
        if (err >= 0)
 
335
                err = au_wbr_nonopq(dentry, err);
 
336
 
 
337
        if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err)))
 
338
                err = -1;
 
339
 
 
340
        AuDbg("%d\n", err);
 
341
        return err;
 
342
}
 
343
 
 
344
/* ---------------------------------------------------------------------- */
 
345
 
 
346
/* round robin */
 
347
static int au_wbr_create_init_rr(struct super_block *sb)
 
348
{
 
349
        int err;
 
350
 
 
351
        err = au_wbr_bu(sb, au_sbend(sb));
 
352
        atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
 
353
        /* smp_mb(); */
 
354
 
 
355
        AuDbg("b%d\n", err);
 
356
        return err;
 
357
}
 
358
 
 
359
static int au_wbr_create_rr(struct dentry *dentry, int isdir)
 
360
{
 
361
        int err, nbr;
 
362
        unsigned int u;
 
363
        aufs_bindex_t bindex, bend;
 
364
        struct super_block *sb;
 
365
        atomic_t *next;
 
366
 
 
367
        err = au_wbr_create_exp(dentry);
 
368
        if (err >= 0)
 
369
                goto out;
 
370
 
 
371
        sb = dentry->d_sb;
 
372
        next = &au_sbi(sb)->si_wbr_rr_next;
 
373
        bend = au_sbend(sb);
 
374
        nbr = bend + 1;
 
375
        for (bindex = 0; bindex <= bend; bindex++) {
 
376
                if (!isdir) {
 
377
                        err = atomic_dec_return(next) + 1;
 
378
                        /* modulo for 0 is meaningless */
 
379
                        if (unlikely(!err))
 
380
                                err = atomic_dec_return(next) + 1;
 
381
                } else
 
382
                        err = atomic_read(next);
 
383
                AuDbg("%d\n", err);
 
384
                u = err;
 
385
                err = u % nbr;
 
386
                AuDbg("%d\n", err);
 
387
                if (!au_br_rdonly(au_sbr(sb, err)))
 
388
                        break;
 
389
                err = -EROFS;
 
390
        }
 
391
 
 
392
        if (err >= 0)
 
393
                err = au_wbr_nonopq(dentry, err);
 
394
 
 
395
out:
 
396
        AuDbg("%d\n", err);
 
397
        return err;
 
398
}
 
399
 
 
400
/* ---------------------------------------------------------------------- */
 
401
 
 
402
/* most free space */
 
403
static void au_mfs(struct dentry *dentry)
 
404
{
 
405
        struct super_block *sb;
 
406
        struct au_branch *br;
 
407
        struct au_wbr_mfs *mfs;
 
408
        aufs_bindex_t bindex, bend;
 
409
        int err;
 
410
        unsigned long long b, bavail;
 
411
        struct path h_path;
 
412
        /* reduce the stack usage */
 
413
        struct kstatfs *st;
 
414
 
 
415
        st = kmalloc(sizeof(*st), GFP_NOFS);
 
416
        if (unlikely(!st)) {
 
417
                AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
 
418
                return;
 
419
        }
 
420
 
 
421
        bavail = 0;
 
422
        sb = dentry->d_sb;
 
423
        mfs = &au_sbi(sb)->si_wbr_mfs;
 
424
        MtxMustLock(&mfs->mfs_lock);
 
425
        mfs->mfs_bindex = -EROFS;
 
426
        mfs->mfsrr_bytes = 0;
 
427
        bend = au_sbend(sb);
 
428
        for (bindex = 0; bindex <= bend; bindex++) {
 
429
                br = au_sbr(sb, bindex);
 
430
                if (au_br_rdonly(br))
 
431
                        continue;
 
432
 
 
433
                /* sb->s_root for NFS is unreliable */
 
434
                h_path.mnt = br->br_mnt;
 
435
                h_path.dentry = h_path.mnt->mnt_root;
 
436
                err = vfs_statfs(&h_path, st);
 
437
                if (unlikely(err)) {
 
438
                        AuWarn1("failed statfs, b%d, %d\n", bindex, err);
 
439
                        continue;
 
440
                }
 
441
 
 
442
                /* when the available size is equal, select the lower one */
 
443
                BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
 
444
                             || sizeof(b) < sizeof(st->f_bsize));
 
445
                b = st->f_bavail * st->f_bsize;
 
446
                br->br_wbr->wbr_bytes = b;
 
447
                if (b >= bavail) {
 
448
                        bavail = b;
 
449
                        mfs->mfs_bindex = bindex;
 
450
                        mfs->mfs_jiffy = jiffies;
 
451
                }
 
452
        }
 
453
 
 
454
        mfs->mfsrr_bytes = bavail;
 
455
        AuDbg("b%d\n", mfs->mfs_bindex);
 
456
        kfree(st);
 
457
}
 
458
 
 
459
static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused)
 
460
{
 
461
        int err;
 
462
        struct super_block *sb;
 
463
        struct au_wbr_mfs *mfs;
 
464
 
 
465
        err = au_wbr_create_exp(dentry);
 
466
        if (err >= 0)
 
467
                goto out;
 
468
 
 
469
        sb = dentry->d_sb;
 
470
        mfs = &au_sbi(sb)->si_wbr_mfs;
 
471
        mutex_lock(&mfs->mfs_lock);
 
472
        if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
 
473
            || mfs->mfs_bindex < 0
 
474
            || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
 
475
                au_mfs(dentry);
 
476
        mutex_unlock(&mfs->mfs_lock);
 
477
        err = mfs->mfs_bindex;
 
478
 
 
479
        if (err >= 0)
 
480
                err = au_wbr_nonopq(dentry, err);
 
481
 
 
482
out:
 
483
        AuDbg("b%d\n", err);
 
484
        return err;
 
485
}
 
486
 
 
487
static int au_wbr_create_init_mfs(struct super_block *sb)
 
488
{
 
489
        struct au_wbr_mfs *mfs;
 
490
 
 
491
        mfs = &au_sbi(sb)->si_wbr_mfs;
 
492
        mutex_init(&mfs->mfs_lock);
 
493
        mfs->mfs_jiffy = 0;
 
494
        mfs->mfs_bindex = -EROFS;
 
495
 
 
496
        return 0;
 
497
}
 
498
 
 
499
static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused)
 
500
{
 
501
        mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock);
 
502
        return 0;
 
503
}
 
504
 
 
505
/* ---------------------------------------------------------------------- */
 
506
 
 
507
/* most free space and then round robin */
 
508
static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir)
 
509
{
 
510
        int err;
 
511
        struct au_wbr_mfs *mfs;
 
512
 
 
513
        err = au_wbr_create_mfs(dentry, isdir);
 
514
        if (err >= 0) {
 
515
                mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs;
 
516
                mutex_lock(&mfs->mfs_lock);
 
517
                if (mfs->mfsrr_bytes < mfs->mfsrr_watermark)
 
518
                        err = au_wbr_create_rr(dentry, isdir);
 
519
                mutex_unlock(&mfs->mfs_lock);
 
520
        }
 
521
 
 
522
        AuDbg("b%d\n", err);
 
523
        return err;
 
524
}
 
525
 
 
526
static int au_wbr_create_init_mfsrr(struct super_block *sb)
 
527
{
 
528
        int err;
 
529
 
 
530
        au_wbr_create_init_mfs(sb); /* ignore */
 
531
        err = au_wbr_create_init_rr(sb);
 
532
 
 
533
        return err;
 
534
}
 
535
 
 
536
/* ---------------------------------------------------------------------- */
 
537
 
 
538
/* top down parent and most free space */
 
539
static int au_wbr_create_pmfs(struct dentry *dentry, int isdir)
 
540
{
 
541
        int err, e2;
 
542
        unsigned long long b;
 
543
        aufs_bindex_t bindex, bstart, bend;
 
544
        struct super_block *sb;
 
545
        struct dentry *parent, *h_parent;
 
546
        struct au_branch *br;
 
547
 
 
548
        err = au_wbr_create_tdp(dentry, isdir);
 
549
        if (unlikely(err < 0))
 
550
                goto out;
 
551
        parent = dget_parent(dentry);
 
552
        bstart = au_dbstart(parent);
 
553
        bend = au_dbtaildir(parent);
 
554
        if (bstart == bend)
 
555
                goto out_parent; /* success */
 
556
 
 
557
        e2 = au_wbr_create_mfs(dentry, isdir);
 
558
        if (e2 < 0)
 
559
                goto out_parent; /* success */
 
560
 
 
561
        /* when the available size is equal, select upper one */
 
562
        sb = dentry->d_sb;
 
563
        br = au_sbr(sb, err);
 
564
        b = br->br_wbr->wbr_bytes;
 
565
        AuDbg("b%d, %llu\n", err, b);
 
566
 
 
567
        for (bindex = bstart; bindex <= bend; bindex++) {
 
568
                h_parent = au_h_dptr(parent, bindex);
 
569
                if (!h_parent || !h_parent->d_inode)
 
570
                        continue;
 
571
 
 
572
                br = au_sbr(sb, bindex);
 
573
                if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) {
 
574
                        b = br->br_wbr->wbr_bytes;
 
575
                        err = bindex;
 
576
                        AuDbg("b%d, %llu\n", err, b);
 
577
                }
 
578
        }
 
579
 
 
580
        if (err >= 0)
 
581
                err = au_wbr_nonopq(dentry, err);
 
582
 
 
583
out_parent:
 
584
        dput(parent);
 
585
out:
 
586
        AuDbg("b%d\n", err);
 
587
        return err;
 
588
}
 
589
 
 
590
/* ---------------------------------------------------------------------- */
 
591
 
 
592
/* policies for copyup */
 
593
 
 
594
/* top down parent */
 
595
static int au_wbr_copyup_tdp(struct dentry *dentry)
 
596
{
 
597
        return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0);
 
598
}
 
599
 
 
600
/* bottom up parent */
 
601
static int au_wbr_copyup_bup(struct dentry *dentry)
 
602
{
 
603
        int err;
 
604
        aufs_bindex_t bindex, bstart;
 
605
        struct dentry *parent, *h_parent;
 
606
        struct super_block *sb;
 
607
 
 
608
        err = -EROFS;
 
609
        sb = dentry->d_sb;
 
610
        parent = dget_parent(dentry);
 
611
        bstart = au_dbstart(parent);
 
612
        for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) {
 
613
                h_parent = au_h_dptr(parent, bindex);
 
614
                if (!h_parent || !h_parent->d_inode)
 
615
                        continue;
 
616
 
 
617
                if (!au_br_rdonly(au_sbr(sb, bindex))) {
 
618
                        err = bindex;
 
619
                        break;
 
620
                }
 
621
        }
 
622
        dput(parent);
 
623
 
 
624
        /* bottom up here */
 
625
        if (unlikely(err < 0))
 
626
                err = au_wbr_bu(sb, bstart - 1);
 
627
 
 
628
        AuDbg("b%d\n", err);
 
629
        return err;
 
630
}
 
631
 
 
632
/* bottom up */
 
633
static int au_wbr_copyup_bu(struct dentry *dentry)
 
634
{
 
635
        int err;
 
636
        aufs_bindex_t bstart;
 
637
 
 
638
        bstart = au_dbstart(dentry);
 
639
        err = au_wbr_bu(dentry->d_sb, bstart);
 
640
        AuDbg("b%d\n", err);
 
641
        if (err > bstart)
 
642
                err = au_wbr_nonopq(dentry, err);
 
643
 
 
644
        AuDbg("b%d\n", err);
 
645
        return err;
 
646
}
 
647
 
 
648
/* ---------------------------------------------------------------------- */
 
649
 
 
650
struct au_wbr_copyup_operations au_wbr_copyup_ops[] = {
 
651
        [AuWbrCopyup_TDP] = {
 
652
                .copyup = au_wbr_copyup_tdp
 
653
        },
 
654
        [AuWbrCopyup_BUP] = {
 
655
                .copyup = au_wbr_copyup_bup
 
656
        },
 
657
        [AuWbrCopyup_BU] = {
 
658
                .copyup = au_wbr_copyup_bu
 
659
        }
 
660
};
 
661
 
 
662
struct au_wbr_create_operations au_wbr_create_ops[] = {
 
663
        [AuWbrCreate_TDP] = {
 
664
                .create = au_wbr_create_tdp
 
665
        },
 
666
        [AuWbrCreate_RR] = {
 
667
                .create = au_wbr_create_rr,
 
668
                .init   = au_wbr_create_init_rr
 
669
        },
 
670
        [AuWbrCreate_MFS] = {
 
671
                .create = au_wbr_create_mfs,
 
672
                .init   = au_wbr_create_init_mfs,
 
673
                .fin    = au_wbr_create_fin_mfs
 
674
        },
 
675
        [AuWbrCreate_MFSV] = {
 
676
                .create = au_wbr_create_mfs,
 
677
                .init   = au_wbr_create_init_mfs,
 
678
                .fin    = au_wbr_create_fin_mfs
 
679
        },
 
680
        [AuWbrCreate_MFSRR] = {
 
681
                .create = au_wbr_create_mfsrr,
 
682
                .init   = au_wbr_create_init_mfsrr,
 
683
                .fin    = au_wbr_create_fin_mfs
 
684
        },
 
685
        [AuWbrCreate_MFSRRV] = {
 
686
                .create = au_wbr_create_mfsrr,
 
687
                .init   = au_wbr_create_init_mfsrr,
 
688
                .fin    = au_wbr_create_fin_mfs
 
689
        },
 
690
        [AuWbrCreate_PMFS] = {
 
691
                .create = au_wbr_create_pmfs,
 
692
                .init   = au_wbr_create_init_mfs,
 
693
                .fin    = au_wbr_create_fin_mfs
 
694
        },
 
695
        [AuWbrCreate_PMFSV] = {
 
696
                .create = au_wbr_create_pmfs,
 
697
                .init   = au_wbr_create_init_mfs,
 
698
                .fin    = au_wbr_create_fin_mfs
 
699
        }
 
700
};