update aufs to it's latest standalone 3.2 branch
[pandora-kernel.git] / fs / aufs / wbr_policy.c
1 /*
2  * Copyright (C) 2005-2013 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->i_flags);
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 static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst,
64                              unsigned int *flags)
65 {
66         int err;
67         struct dentry *opq_dentry;
68
69         opq_dentry = au_diropq_create(dentry, bdst);
70         err = PTR_ERR(opq_dentry);
71         if (IS_ERR(opq_dentry))
72                 goto out;
73         dput(opq_dentry);
74         au_fset_cpdown(*flags, DIROPQ);
75
76 out:
77         return err;
78 }
79
80 static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent,
81                             struct inode *dir, aufs_bindex_t bdst)
82 {
83         int err;
84         struct path h_path;
85         struct au_branch *br;
86
87         br = au_sbr(dentry->d_sb, bdst);
88         h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
89         err = PTR_ERR(h_path.dentry);
90         if (IS_ERR(h_path.dentry))
91                 goto out;
92
93         err = 0;
94         if (h_path.dentry->d_inode) {
95                 h_path.mnt = au_br_mnt(br);
96                 err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path,
97                                           dentry);
98         }
99         dput(h_path.dentry);
100
101 out:
102         return err;
103 }
104
105 static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst,
106                          struct au_pin *pin,
107                          struct dentry *h_parent, void *arg)
108 {
109         int err, rerr;
110         aufs_bindex_t bopq, bstart;
111         struct path h_path;
112         struct dentry *parent;
113         struct inode *h_dir, *h_inode, *inode, *dir;
114         unsigned int *flags = arg;
115
116         bstart = au_dbstart(dentry);
117         /* dentry is di-locked */
118         parent = dget_parent(dentry);
119         dir = parent->d_inode;
120         h_dir = h_parent->d_inode;
121         AuDebugOn(h_dir != au_h_iptr(dir, bdst));
122         IMustLock(h_dir);
123
124         err = au_lkup_neg(dentry, bdst, /*wh*/0);
125         if (unlikely(err < 0))
126                 goto out;
127         h_path.dentry = au_h_dptr(dentry, bdst);
128         h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst);
129         err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path,
130                               S_IRWXU | S_IRUGO | S_IXUGO);
131         if (unlikely(err))
132                 goto out_put;
133         au_fset_cpdown(*flags, MADE_DIR);
134
135         bopq = au_dbdiropq(dentry);
136         au_fclr_cpdown(*flags, WHED);
137         au_fclr_cpdown(*flags, DIROPQ);
138         if (au_dbwh(dentry) == bdst)
139                 au_fset_cpdown(*flags, WHED);
140         if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst)
141                 au_fset_cpdown(*flags, PARENT_OPQ);
142         h_inode = h_path.dentry->d_inode;
143         mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
144         if (au_ftest_cpdown(*flags, WHED)) {
145                 err = au_cpdown_dir_opq(dentry, bdst, flags);
146                 if (unlikely(err)) {
147                         mutex_unlock(&h_inode->i_mutex);
148                         goto out_dir;
149                 }
150         }
151
152         err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart));
153         mutex_unlock(&h_inode->i_mutex);
154         if (unlikely(err))
155                 goto out_opq;
156
157         if (au_ftest_cpdown(*flags, WHED)) {
158                 err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst);
159                 if (unlikely(err))
160                         goto out_opq;
161         }
162
163         inode = dentry->d_inode;
164         if (au_ibend(inode) < bdst)
165                 au_set_ibend(inode, bdst);
166         au_set_h_iptr(inode, bdst, au_igrab(h_inode),
167                       au_hi_flags(inode, /*isdir*/1));
168         goto out; /* success */
169
170         /* revert */
171 out_opq:
172         if (au_ftest_cpdown(*flags, DIROPQ)) {
173                 mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
174                 rerr = au_diropq_remove(dentry, bdst);
175                 mutex_unlock(&h_inode->i_mutex);
176                 if (unlikely(rerr)) {
177                         AuIOErr("failed removing diropq for %.*s b%d (%d)\n",
178                                 AuDLNPair(dentry), bdst, rerr);
179                         err = -EIO;
180                         goto out;
181                 }
182         }
183 out_dir:
184         if (au_ftest_cpdown(*flags, MADE_DIR)) {
185                 rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
186                 if (unlikely(rerr)) {
187                         AuIOErr("failed removing %.*s b%d (%d)\n",
188                                 AuDLNPair(dentry), bdst, rerr);
189                         err = -EIO;
190                 }
191         }
192 out_put:
193         au_set_h_dptr(dentry, bdst, NULL);
194         if (au_dbend(dentry) == bdst)
195                 au_update_dbend(dentry);
196 out:
197         dput(parent);
198         return err;
199 }
200
201 int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
202 {
203         int err;
204         unsigned int flags;
205
206         flags = 0;
207         err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags);
208
209         return err;
210 }
211
212 /* ---------------------------------------------------------------------- */
213
214 /* policies for create */
215
216 static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
217 {
218         int err, i, j, ndentry;
219         aufs_bindex_t bopq;
220         struct au_dcsub_pages dpages;
221         struct au_dpage *dpage;
222         struct dentry **dentries, *parent, *d;
223
224         err = au_dpages_init(&dpages, GFP_NOFS);
225         if (unlikely(err))
226                 goto out;
227         parent = dget_parent(dentry);
228         err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0);
229         if (unlikely(err))
230                 goto out_free;
231
232         err = bindex;
233         for (i = 0; i < dpages.ndpage; i++) {
234                 dpage = dpages.dpages + i;
235                 dentries = dpage->dentries;
236                 ndentry = dpage->ndentry;
237                 for (j = 0; j < ndentry; j++) {
238                         d = dentries[j];
239                         di_read_lock_parent2(d, !AuLock_IR);
240                         bopq = au_dbdiropq(d);
241                         di_read_unlock(d, !AuLock_IR);
242                         if (bopq >= 0 && bopq < err)
243                                 err = bopq;
244                 }
245         }
246
247 out_free:
248         dput(parent);
249         au_dpages_free(&dpages);
250 out:
251         return err;
252 }
253
254 static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex)
255 {
256         for (; bindex >= 0; bindex--)
257                 if (!au_br_rdonly(au_sbr(sb, bindex)))
258                         return bindex;
259         return -EROFS;
260 }
261
262 /* top down parent */
263 static int au_wbr_create_tdp(struct dentry *dentry,
264                              unsigned int flags __maybe_unused)
265 {
266         int err;
267         aufs_bindex_t bstart, bindex;
268         struct super_block *sb;
269         struct dentry *parent, *h_parent;
270
271         sb = dentry->d_sb;
272         bstart = au_dbstart(dentry);
273         err = bstart;
274         if (!au_br_rdonly(au_sbr(sb, bstart)))
275                 goto out;
276
277         err = -EROFS;
278         parent = dget_parent(dentry);
279         for (bindex = au_dbstart(parent); bindex < bstart; bindex++) {
280                 h_parent = au_h_dptr(parent, bindex);
281                 if (!h_parent || !h_parent->d_inode)
282                         continue;
283
284                 if (!au_br_rdonly(au_sbr(sb, bindex))) {
285                         err = bindex;
286                         break;
287                 }
288         }
289         dput(parent);
290
291         /* bottom up here */
292         if (unlikely(err < 0)) {
293                 err = au_wbr_bu(sb, bstart - 1);
294                 if (err >= 0)
295                         err = au_wbr_nonopq(dentry, err);
296         }
297
298 out:
299         AuDbg("b%d\n", err);
300         return err;
301 }
302
303 /* ---------------------------------------------------------------------- */
304
305 /* an exception for the policy other than tdp */
306 static int au_wbr_create_exp(struct dentry *dentry)
307 {
308         int err;
309         aufs_bindex_t bwh, bdiropq;
310         struct dentry *parent;
311
312         err = -1;
313         bwh = au_dbwh(dentry);
314         parent = dget_parent(dentry);
315         bdiropq = au_dbdiropq(parent);
316         if (bwh >= 0) {
317                 if (bdiropq >= 0)
318                         err = min(bdiropq, bwh);
319                 else
320                         err = bwh;
321                 AuDbg("%d\n", err);
322         } else if (bdiropq >= 0) {
323                 err = bdiropq;
324                 AuDbg("%d\n", err);
325         }
326         dput(parent);
327
328         if (err >= 0)
329                 err = au_wbr_nonopq(dentry, err);
330
331         if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err)))
332                 err = -1;
333
334         AuDbg("%d\n", err);
335         return err;
336 }
337
338 /* ---------------------------------------------------------------------- */
339
340 /* round robin */
341 static int au_wbr_create_init_rr(struct super_block *sb)
342 {
343         int err;
344
345         err = au_wbr_bu(sb, au_sbend(sb));
346         atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
347         /* smp_mb(); */
348
349         AuDbg("b%d\n", err);
350         return err;
351 }
352
353 static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags)
354 {
355         int err, nbr;
356         unsigned int u;
357         aufs_bindex_t bindex, bend;
358         struct super_block *sb;
359         atomic_t *next;
360
361         err = au_wbr_create_exp(dentry);
362         if (err >= 0)
363                 goto out;
364
365         sb = dentry->d_sb;
366         next = &au_sbi(sb)->si_wbr_rr_next;
367         bend = au_sbend(sb);
368         nbr = bend + 1;
369         for (bindex = 0; bindex <= bend; bindex++) {
370                 if (!au_ftest_wbr(flags, DIR)) {
371                         err = atomic_dec_return(next) + 1;
372                         /* modulo for 0 is meaningless */
373                         if (unlikely(!err))
374                                 err = atomic_dec_return(next) + 1;
375                 } else
376                         err = atomic_read(next);
377                 AuDbg("%d\n", err);
378                 u = err;
379                 err = u % nbr;
380                 AuDbg("%d\n", err);
381                 if (!au_br_rdonly(au_sbr(sb, err)))
382                         break;
383                 err = -EROFS;
384         }
385
386         if (err >= 0)
387                 err = au_wbr_nonopq(dentry, err);
388
389 out:
390         AuDbg("%d\n", err);
391         return err;
392 }
393
394 /* ---------------------------------------------------------------------- */
395
396 /* most free space */
397 static void au_mfs(struct dentry *dentry, struct dentry *parent)
398 {
399         struct super_block *sb;
400         struct au_branch *br;
401         struct au_wbr_mfs *mfs;
402         struct dentry *h_parent;
403         aufs_bindex_t bindex, bend;
404         int err;
405         unsigned long long b, bavail;
406         struct path h_path;
407         /* reduce the stack usage */
408         struct kstatfs *st;
409
410         st = kmalloc(sizeof(*st), GFP_NOFS);
411         if (unlikely(!st)) {
412                 AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
413                 return;
414         }
415
416         bavail = 0;
417         sb = dentry->d_sb;
418         mfs = &au_sbi(sb)->si_wbr_mfs;
419         MtxMustLock(&mfs->mfs_lock);
420         mfs->mfs_bindex = -EROFS;
421         mfs->mfsrr_bytes = 0;
422         if (!parent) {
423                 bindex = 0;
424                 bend = au_sbend(sb);
425         } else {
426                 bindex = au_dbstart(parent);
427                 bend = au_dbtaildir(parent);
428         }
429
430         for (; bindex <= bend; bindex++) {
431                 if (parent) {
432                         h_parent = au_h_dptr(parent, bindex);
433                         if (!h_parent || !h_parent->d_inode)
434                                 continue;
435                 }
436                 br = au_sbr(sb, bindex);
437                 if (au_br_rdonly(br))
438                         continue;
439
440                 /* sb->s_root for NFS is unreliable */
441                 h_path.mnt = au_br_mnt(br);
442                 h_path.dentry = h_path.mnt->mnt_root;
443                 err = vfs_statfs(&h_path, st);
444                 if (unlikely(err)) {
445                         AuWarn1("failed statfs, b%d, %d\n", bindex, err);
446                         continue;
447                 }
448
449                 /* when the available size is equal, select the lower one */
450                 BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
451                              || sizeof(b) < sizeof(st->f_bsize));
452                 b = st->f_bavail * st->f_bsize;
453                 br->br_wbr->wbr_bytes = b;
454                 if (b >= bavail) {
455                         bavail = b;
456                         mfs->mfs_bindex = bindex;
457                         mfs->mfs_jiffy = jiffies;
458                 }
459         }
460
461         mfs->mfsrr_bytes = bavail;
462         AuDbg("b%d\n", mfs->mfs_bindex);
463         kfree(st);
464 }
465
466 static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags)
467 {
468         int err;
469         struct dentry *parent;
470         struct super_block *sb;
471         struct au_wbr_mfs *mfs;
472
473         err = au_wbr_create_exp(dentry);
474         if (err >= 0)
475                 goto out;
476
477         sb = dentry->d_sb;
478         parent = NULL;
479         if (au_ftest_wbr(flags, PARENT))
480                 parent = dget_parent(dentry);
481         mfs = &au_sbi(sb)->si_wbr_mfs;
482         mutex_lock(&mfs->mfs_lock);
483         if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
484             || mfs->mfs_bindex < 0
485             || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
486                 au_mfs(dentry, parent);
487         mutex_unlock(&mfs->mfs_lock);
488         err = mfs->mfs_bindex;
489         dput(parent);
490
491         if (err >= 0)
492                 err = au_wbr_nonopq(dentry, err);
493
494 out:
495         AuDbg("b%d\n", err);
496         return err;
497 }
498
499 static int au_wbr_create_init_mfs(struct super_block *sb)
500 {
501         struct au_wbr_mfs *mfs;
502
503         mfs = &au_sbi(sb)->si_wbr_mfs;
504         mutex_init(&mfs->mfs_lock);
505         mfs->mfs_jiffy = 0;
506         mfs->mfs_bindex = -EROFS;
507
508         return 0;
509 }
510
511 static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused)
512 {
513         mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock);
514         return 0;
515 }
516
517 /* ---------------------------------------------------------------------- */
518
519 /* most free space and then round robin */
520 static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags)
521 {
522         int err;
523         struct au_wbr_mfs *mfs;
524
525         err = au_wbr_create_mfs(dentry, flags);
526         if (err >= 0) {
527                 mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs;
528                 mutex_lock(&mfs->mfs_lock);
529                 if (mfs->mfsrr_bytes < mfs->mfsrr_watermark)
530                         err = au_wbr_create_rr(dentry, flags);
531                 mutex_unlock(&mfs->mfs_lock);
532         }
533
534         AuDbg("b%d\n", err);
535         return err;
536 }
537
538 static int au_wbr_create_init_mfsrr(struct super_block *sb)
539 {
540         int err;
541
542         au_wbr_create_init_mfs(sb); /* ignore */
543         err = au_wbr_create_init_rr(sb);
544
545         return err;
546 }
547
548 /* ---------------------------------------------------------------------- */
549
550 /* top down parent and most free space */
551 static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags)
552 {
553         int err, e2;
554         unsigned long long b;
555         aufs_bindex_t bindex, bstart, bend;
556         struct super_block *sb;
557         struct dentry *parent, *h_parent;
558         struct au_branch *br;
559
560         err = au_wbr_create_tdp(dentry, flags);
561         if (unlikely(err < 0))
562                 goto out;
563         parent = dget_parent(dentry);
564         bstart = au_dbstart(parent);
565         bend = au_dbtaildir(parent);
566         if (bstart == bend)
567                 goto out_parent; /* success */
568
569         e2 = au_wbr_create_mfs(dentry, flags);
570         if (e2 < 0)
571                 goto out_parent; /* success */
572
573         /* when the available size is equal, select upper one */
574         sb = dentry->d_sb;
575         br = au_sbr(sb, err);
576         b = br->br_wbr->wbr_bytes;
577         AuDbg("b%d, %llu\n", err, b);
578
579         for (bindex = bstart; bindex <= bend; bindex++) {
580                 h_parent = au_h_dptr(parent, bindex);
581                 if (!h_parent || !h_parent->d_inode)
582                         continue;
583
584                 br = au_sbr(sb, bindex);
585                 if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) {
586                         b = br->br_wbr->wbr_bytes;
587                         err = bindex;
588                         AuDbg("b%d, %llu\n", err, b);
589                 }
590         }
591
592         if (err >= 0)
593                 err = au_wbr_nonopq(dentry, err);
594
595 out_parent:
596         dput(parent);
597 out:
598         AuDbg("b%d\n", err);
599         return err;
600 }
601
602 /* ---------------------------------------------------------------------- */
603
604 /*
605  * - top down parent
606  * - most free space with parent
607  * - most free space round-robin regardless parent
608  */
609 static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags)
610 {
611         int err;
612         unsigned long long watermark;
613         struct super_block *sb;
614         struct au_branch *br;
615         struct au_wbr_mfs *mfs;
616
617         err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT);
618         if (unlikely(err < 0))
619                 goto out;
620
621         sb = dentry->d_sb;
622         br = au_sbr(sb, err);
623         mfs = &au_sbi(sb)->si_wbr_mfs;
624         mutex_lock(&mfs->mfs_lock);
625         watermark = mfs->mfsrr_watermark;
626         mutex_unlock(&mfs->mfs_lock);
627         if (br->br_wbr->wbr_bytes < watermark)
628                 /* regardless the parent dir */
629                 err = au_wbr_create_mfsrr(dentry, flags);
630
631 out:
632         AuDbg("b%d\n", err);
633         return err;
634 }
635
636 /* ---------------------------------------------------------------------- */
637
638 /* policies for copyup */
639
640 /* top down parent */
641 static int au_wbr_copyup_tdp(struct dentry *dentry)
642 {
643         return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0);
644 }
645
646 /* bottom up parent */
647 static int au_wbr_copyup_bup(struct dentry *dentry)
648 {
649         int err;
650         aufs_bindex_t bindex, bstart;
651         struct dentry *parent, *h_parent;
652         struct super_block *sb;
653
654         err = -EROFS;
655         sb = dentry->d_sb;
656         parent = dget_parent(dentry);
657         bstart = au_dbstart(parent);
658         for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) {
659                 h_parent = au_h_dptr(parent, bindex);
660                 if (!h_parent || !h_parent->d_inode)
661                         continue;
662
663                 if (!au_br_rdonly(au_sbr(sb, bindex))) {
664                         err = bindex;
665                         break;
666                 }
667         }
668         dput(parent);
669
670         /* bottom up here */
671         if (unlikely(err < 0))
672                 err = au_wbr_bu(sb, bstart - 1);
673
674         AuDbg("b%d\n", err);
675         return err;
676 }
677
678 /* bottom up */
679 static int au_wbr_copyup_bu(struct dentry *dentry)
680 {
681         int err;
682         aufs_bindex_t bstart;
683
684         bstart = au_dbstart(dentry);
685         err = au_wbr_bu(dentry->d_sb, bstart);
686         AuDbg("b%d\n", err);
687         if (err > bstart)
688                 err = au_wbr_nonopq(dentry, err);
689
690         AuDbg("b%d\n", err);
691         return err;
692 }
693
694 /* ---------------------------------------------------------------------- */
695
696 struct au_wbr_copyup_operations au_wbr_copyup_ops[] = {
697         [AuWbrCopyup_TDP] = {
698                 .copyup = au_wbr_copyup_tdp
699         },
700         [AuWbrCopyup_BUP] = {
701                 .copyup = au_wbr_copyup_bup
702         },
703         [AuWbrCopyup_BU] = {
704                 .copyup = au_wbr_copyup_bu
705         }
706 };
707
708 struct au_wbr_create_operations au_wbr_create_ops[] = {
709         [AuWbrCreate_TDP] = {
710                 .create = au_wbr_create_tdp
711         },
712         [AuWbrCreate_RR] = {
713                 .create = au_wbr_create_rr,
714                 .init   = au_wbr_create_init_rr
715         },
716         [AuWbrCreate_MFS] = {
717                 .create = au_wbr_create_mfs,
718                 .init   = au_wbr_create_init_mfs,
719                 .fin    = au_wbr_create_fin_mfs
720         },
721         [AuWbrCreate_MFSV] = {
722                 .create = au_wbr_create_mfs,
723                 .init   = au_wbr_create_init_mfs,
724                 .fin    = au_wbr_create_fin_mfs
725         },
726         [AuWbrCreate_MFSRR] = {
727                 .create = au_wbr_create_mfsrr,
728                 .init   = au_wbr_create_init_mfsrr,
729                 .fin    = au_wbr_create_fin_mfs
730         },
731         [AuWbrCreate_MFSRRV] = {
732                 .create = au_wbr_create_mfsrr,
733                 .init   = au_wbr_create_init_mfsrr,
734                 .fin    = au_wbr_create_fin_mfs
735         },
736         [AuWbrCreate_PMFS] = {
737                 .create = au_wbr_create_pmfs,
738                 .init   = au_wbr_create_init_mfs,
739                 .fin    = au_wbr_create_fin_mfs
740         },
741         [AuWbrCreate_PMFSV] = {
742                 .create = au_wbr_create_pmfs,
743                 .init   = au_wbr_create_init_mfs,
744                 .fin    = au_wbr_create_fin_mfs
745         },
746         [AuWbrCreate_PMFSRR] = {
747                 .create = au_wbr_create_pmfsrr,
748                 .init   = au_wbr_create_init_mfsrr,
749                 .fin    = au_wbr_create_fin_mfs
750         },
751         [AuWbrCreate_PMFSRRV] = {
752                 .create = au_wbr_create_pmfsrr,
753                 .init   = au_wbr_create_init_mfsrr,
754                 .fin    = au_wbr_create_fin_mfs
755         }
756 };