]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - fs/aufs/wbr_policy.c
UBUNTU: SAUCE: aufs -- Convert to use xattr handlers
[mirror_ubuntu-zesty-kernel.git] / fs / aufs / wbr_policy.c
CommitLineData
5b88fdd9
SF
1/*
2 * Copyright (C) 2005-2016 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, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * policies for selecting one among multiple writable branches
20 */
21
22#include <linux/statfs.h>
23#include "aufs.h"
24
25/* subset of cpup_attr() */
26static noinline_for_stack
27int au_cpdown_attr(struct path *h_path, struct dentry *h_src)
28{
29 int err, sbits;
30 struct iattr ia;
31 struct inode *h_isrc;
32
33 h_isrc = d_inode(h_src);
34 ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID;
35 ia.ia_mode = h_isrc->i_mode;
36 ia.ia_uid = h_isrc->i_uid;
37 ia.ia_gid = h_isrc->i_gid;
38 sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
39 au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags);
40 /* no delegation since it is just created */
41 err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL);
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, /*delegated*/NULL);
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
63static 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
76out:
77 return err;
78}
79
80static 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 (d_is_positive(h_path.dentry)) {
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
101out:
102 return err;
103}
104
105static 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, btop;
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 btop = au_dbtop(dentry);
117 /* dentry is di-locked */
118 parent = dget_parent(dentry);
119 dir = d_inode(parent);
120 h_dir = d_inode(h_parent);
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 = d_inode(h_path.dentry);
143 inode_lock_nested(h_inode, AuLsc_I_CHILD);
144 if (au_ftest_cpdown(*flags, WHED)) {
145 err = au_cpdown_dir_opq(dentry, bdst, flags);
146 if (unlikely(err)) {
147 inode_unlock(h_inode);
148 goto out_dir;
149 }
150 }
151
152 err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop));
153 inode_unlock(h_inode);
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 = d_inode(dentry);
164 if (au_ibbot(inode) < bdst)
165 au_set_ibbot(inode, bdst);
166 au_set_h_iptr(inode, bdst, au_igrab(h_inode),
167 au_hi_flags(inode, /*isdir*/1));
168 au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0);
169 goto out; /* success */
170
171 /* revert */
172out_opq:
173 if (au_ftest_cpdown(*flags, DIROPQ)) {
174 inode_lock_nested(h_inode, AuLsc_I_CHILD);
175 rerr = au_diropq_remove(dentry, bdst);
176 inode_unlock(h_inode);
177 if (unlikely(rerr)) {
178 AuIOErr("failed removing diropq for %pd b%d (%d)\n",
179 dentry, bdst, rerr);
180 err = -EIO;
181 goto out;
182 }
183 }
184out_dir:
185 if (au_ftest_cpdown(*flags, MADE_DIR)) {
186 rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
187 if (unlikely(rerr)) {
188 AuIOErr("failed removing %pd b%d (%d)\n",
189 dentry, bdst, rerr);
190 err = -EIO;
191 }
192 }
193out_put:
194 au_set_h_dptr(dentry, bdst, NULL);
195 if (au_dbbot(dentry) == bdst)
196 au_update_dbbot(dentry);
197out:
198 dput(parent);
199 return err;
200}
201
202int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
203{
204 int err;
205 unsigned int flags;
206
207 flags = 0;
208 err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags);
209
210 return err;
211}
212
213/* ---------------------------------------------------------------------- */
214
215/* policies for create */
216
217int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
218{
219 int err, i, j, ndentry;
220 aufs_bindex_t bopq;
221 struct au_dcsub_pages dpages;
222 struct au_dpage *dpage;
223 struct dentry **dentries, *parent, *d;
224
225 err = au_dpages_init(&dpages, GFP_NOFS);
226 if (unlikely(err))
227 goto out;
228 parent = dget_parent(dentry);
229 err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0);
230 if (unlikely(err))
231 goto out_free;
232
233 err = bindex;
234 for (i = 0; i < dpages.ndpage; i++) {
235 dpage = dpages.dpages + i;
236 dentries = dpage->dentries;
237 ndentry = dpage->ndentry;
238 for (j = 0; j < ndentry; j++) {
239 d = dentries[j];
240 di_read_lock_parent2(d, !AuLock_IR);
241 bopq = au_dbdiropq(d);
242 di_read_unlock(d, !AuLock_IR);
243 if (bopq >= 0 && bopq < err)
244 err = bopq;
245 }
246 }
247
248out_free:
249 dput(parent);
250 au_dpages_free(&dpages);
251out:
252 return err;
253}
254
255static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex)
256{
257 for (; bindex >= 0; bindex--)
258 if (!au_br_rdonly(au_sbr(sb, bindex)))
259 return bindex;
260 return -EROFS;
261}
262
263/* top down parent */
264static int au_wbr_create_tdp(struct dentry *dentry,
265 unsigned int flags __maybe_unused)
266{
267 int err;
268 aufs_bindex_t btop, bindex;
269 struct super_block *sb;
270 struct dentry *parent, *h_parent;
271
272 sb = dentry->d_sb;
273 btop = au_dbtop(dentry);
274 err = btop;
275 if (!au_br_rdonly(au_sbr(sb, btop)))
276 goto out;
277
278 err = -EROFS;
279 parent = dget_parent(dentry);
280 for (bindex = au_dbtop(parent); bindex < btop; bindex++) {
281 h_parent = au_h_dptr(parent, bindex);
282 if (!h_parent || d_is_negative(h_parent))
283 continue;
284
285 if (!au_br_rdonly(au_sbr(sb, bindex))) {
286 err = bindex;
287 break;
288 }
289 }
290 dput(parent);
291
292 /* bottom up here */
293 if (unlikely(err < 0)) {
294 err = au_wbr_bu(sb, btop - 1);
295 if (err >= 0)
296 err = au_wbr_nonopq(dentry, err);
297 }
298
299out:
300 AuDbg("b%d\n", err);
301 return err;
302}
303
304/* ---------------------------------------------------------------------- */
305
306/* an exception for the policy other than tdp */
307static int au_wbr_create_exp(struct dentry *dentry)
308{
309 int err;
310 aufs_bindex_t bwh, bdiropq;
311 struct dentry *parent;
312
313 err = -1;
314 bwh = au_dbwh(dentry);
315 parent = dget_parent(dentry);
316 bdiropq = au_dbdiropq(parent);
317 if (bwh >= 0) {
318 if (bdiropq >= 0)
319 err = min(bdiropq, bwh);
320 else
321 err = bwh;
322 AuDbg("%d\n", err);
323 } else if (bdiropq >= 0) {
324 err = bdiropq;
325 AuDbg("%d\n", err);
326 }
327 dput(parent);
328
329 if (err >= 0)
330 err = au_wbr_nonopq(dentry, err);
331
332 if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err)))
333 err = -1;
334
335 AuDbg("%d\n", err);
336 return err;
337}
338
339/* ---------------------------------------------------------------------- */
340
341/* round robin */
342static int au_wbr_create_init_rr(struct super_block *sb)
343{
344 int err;
345
346 err = au_wbr_bu(sb, au_sbbot(sb));
347 atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
348 /* smp_mb(); */
349
350 AuDbg("b%d\n", err);
351 return err;
352}
353
354static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags)
355{
356 int err, nbr;
357 unsigned int u;
358 aufs_bindex_t bindex, bbot;
359 struct super_block *sb;
360 atomic_t *next;
361
362 err = au_wbr_create_exp(dentry);
363 if (err >= 0)
364 goto out;
365
366 sb = dentry->d_sb;
367 next = &au_sbi(sb)->si_wbr_rr_next;
368 bbot = au_sbbot(sb);
369 nbr = bbot + 1;
370 for (bindex = 0; bindex <= bbot; bindex++) {
371 if (!au_ftest_wbr(flags, DIR)) {
372 err = atomic_dec_return(next) + 1;
373 /* modulo for 0 is meaningless */
374 if (unlikely(!err))
375 err = atomic_dec_return(next) + 1;
376 } else
377 err = atomic_read(next);
378 AuDbg("%d\n", err);
379 u = err;
380 err = u % nbr;
381 AuDbg("%d\n", err);
382 if (!au_br_rdonly(au_sbr(sb, err)))
383 break;
384 err = -EROFS;
385 }
386
387 if (err >= 0)
388 err = au_wbr_nonopq(dentry, err);
389
390out:
391 AuDbg("%d\n", err);
392 return err;
393}
394
395/* ---------------------------------------------------------------------- */
396
397/* most free space */
398static void au_mfs(struct dentry *dentry, struct dentry *parent)
399{
400 struct super_block *sb;
401 struct au_branch *br;
402 struct au_wbr_mfs *mfs;
403 struct dentry *h_parent;
404 aufs_bindex_t bindex, bbot;
405 int err;
406 unsigned long long b, bavail;
407 struct path h_path;
408 /* reduce the stack usage */
409 struct kstatfs *st;
410
411 st = kmalloc(sizeof(*st), GFP_NOFS);
412 if (unlikely(!st)) {
413 AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
414 return;
415 }
416
417 bavail = 0;
418 sb = dentry->d_sb;
419 mfs = &au_sbi(sb)->si_wbr_mfs;
420 MtxMustLock(&mfs->mfs_lock);
421 mfs->mfs_bindex = -EROFS;
422 mfs->mfsrr_bytes = 0;
423 if (!parent) {
424 bindex = 0;
425 bbot = au_sbbot(sb);
426 } else {
427 bindex = au_dbtop(parent);
428 bbot = au_dbtaildir(parent);
429 }
430
431 for (; bindex <= bbot; bindex++) {
432 if (parent) {
433 h_parent = au_h_dptr(parent, bindex);
434 if (!h_parent || d_is_negative(h_parent))
435 continue;
436 }
437 br = au_sbr(sb, bindex);
438 if (au_br_rdonly(br))
439 continue;
440
441 /* sb->s_root for NFS is unreliable */
442 h_path.mnt = au_br_mnt(br);
443 h_path.dentry = h_path.mnt->mnt_root;
444 err = vfs_statfs(&h_path, st);
445 if (unlikely(err)) {
446 AuWarn1("failed statfs, b%d, %d\n", bindex, err);
447 continue;
448 }
449
450 /* when the available size is equal, select the lower one */
451 BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
452 || sizeof(b) < sizeof(st->f_bsize));
453 b = st->f_bavail * st->f_bsize;
454 br->br_wbr->wbr_bytes = b;
455 if (b >= bavail) {
456 bavail = b;
457 mfs->mfs_bindex = bindex;
458 mfs->mfs_jiffy = jiffies;
459 }
460 }
461
462 mfs->mfsrr_bytes = bavail;
463 AuDbg("b%d\n", mfs->mfs_bindex);
464 au_delayed_kfree(st);
465}
466
467static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags)
468{
469 int err;
470 struct dentry *parent;
471 struct super_block *sb;
472 struct au_wbr_mfs *mfs;
473
474 err = au_wbr_create_exp(dentry);
475 if (err >= 0)
476 goto out;
477
478 sb = dentry->d_sb;
479 parent = NULL;
480 if (au_ftest_wbr(flags, PARENT))
481 parent = dget_parent(dentry);
482 mfs = &au_sbi(sb)->si_wbr_mfs;
483 mutex_lock(&mfs->mfs_lock);
484 if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
485 || mfs->mfs_bindex < 0
486 || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
487 au_mfs(dentry, parent);
488 mutex_unlock(&mfs->mfs_lock);
489 err = mfs->mfs_bindex;
490 dput(parent);
491
492 if (err >= 0)
493 err = au_wbr_nonopq(dentry, err);
494
495out:
496 AuDbg("b%d\n", err);
497 return err;
498}
499
500static int au_wbr_create_init_mfs(struct super_block *sb)
501{
502 struct au_wbr_mfs *mfs;
503
504 mfs = &au_sbi(sb)->si_wbr_mfs;
505 mutex_init(&mfs->mfs_lock);
506 mfs->mfs_jiffy = 0;
507 mfs->mfs_bindex = -EROFS;
508
509 return 0;
510}
511
512static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused)
513{
514 mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock);
515 return 0;
516}
517
518/* ---------------------------------------------------------------------- */
519
520/* most free space and then round robin */
521static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags)
522{
523 int err;
524 struct au_wbr_mfs *mfs;
525
526 err = au_wbr_create_mfs(dentry, flags);
527 if (err >= 0) {
528 mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs;
529 mutex_lock(&mfs->mfs_lock);
530 if (mfs->mfsrr_bytes < mfs->mfsrr_watermark)
531 err = au_wbr_create_rr(dentry, flags);
532 mutex_unlock(&mfs->mfs_lock);
533 }
534
535 AuDbg("b%d\n", err);
536 return err;
537}
538
539static int au_wbr_create_init_mfsrr(struct super_block *sb)
540{
541 int err;
542
543 au_wbr_create_init_mfs(sb); /* ignore */
544 err = au_wbr_create_init_rr(sb);
545
546 return err;
547}
548
549/* ---------------------------------------------------------------------- */
550
551/* top down parent and most free space */
552static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags)
553{
554 int err, e2;
555 unsigned long long b;
556 aufs_bindex_t bindex, btop, bbot;
557 struct super_block *sb;
558 struct dentry *parent, *h_parent;
559 struct au_branch *br;
560
561 err = au_wbr_create_tdp(dentry, flags);
562 if (unlikely(err < 0))
563 goto out;
564 parent = dget_parent(dentry);
565 btop = au_dbtop(parent);
566 bbot = au_dbtaildir(parent);
567 if (btop == bbot)
568 goto out_parent; /* success */
569
570 e2 = au_wbr_create_mfs(dentry, flags);
571 if (e2 < 0)
572 goto out_parent; /* success */
573
574 /* when the available size is equal, select upper one */
575 sb = dentry->d_sb;
576 br = au_sbr(sb, err);
577 b = br->br_wbr->wbr_bytes;
578 AuDbg("b%d, %llu\n", err, b);
579
580 for (bindex = btop; bindex <= bbot; bindex++) {
581 h_parent = au_h_dptr(parent, bindex);
582 if (!h_parent || d_is_negative(h_parent))
583 continue;
584
585 br = au_sbr(sb, bindex);
586 if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) {
587 b = br->br_wbr->wbr_bytes;
588 err = bindex;
589 AuDbg("b%d, %llu\n", err, b);
590 }
591 }
592
593 if (err >= 0)
594 err = au_wbr_nonopq(dentry, err);
595
596out_parent:
597 dput(parent);
598out:
599 AuDbg("b%d\n", err);
600 return err;
601}
602
603/* ---------------------------------------------------------------------- */
604
605/*
606 * - top down parent
607 * - most free space with parent
608 * - most free space round-robin regardless parent
609 */
610static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags)
611{
612 int err;
613 unsigned long long watermark;
614 struct super_block *sb;
615 struct au_branch *br;
616 struct au_wbr_mfs *mfs;
617
618 err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT);
619 if (unlikely(err < 0))
620 goto out;
621
622 sb = dentry->d_sb;
623 br = au_sbr(sb, err);
624 mfs = &au_sbi(sb)->si_wbr_mfs;
625 mutex_lock(&mfs->mfs_lock);
626 watermark = mfs->mfsrr_watermark;
627 mutex_unlock(&mfs->mfs_lock);
628 if (br->br_wbr->wbr_bytes < watermark)
629 /* regardless the parent dir */
630 err = au_wbr_create_mfsrr(dentry, flags);
631
632out:
633 AuDbg("b%d\n", err);
634 return err;
635}
636
637/* ---------------------------------------------------------------------- */
638
639/* policies for copyup */
640
641/* top down parent */
642static int au_wbr_copyup_tdp(struct dentry *dentry)
643{
644 return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0);
645}
646
647/* bottom up parent */
648static int au_wbr_copyup_bup(struct dentry *dentry)
649{
650 int err;
651 aufs_bindex_t bindex, btop;
652 struct dentry *parent, *h_parent;
653 struct super_block *sb;
654
655 err = -EROFS;
656 sb = dentry->d_sb;
657 parent = dget_parent(dentry);
658 btop = au_dbtop(parent);
659 for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) {
660 h_parent = au_h_dptr(parent, bindex);
661 if (!h_parent || d_is_negative(h_parent))
662 continue;
663
664 if (!au_br_rdonly(au_sbr(sb, bindex))) {
665 err = bindex;
666 break;
667 }
668 }
669 dput(parent);
670
671 /* bottom up here */
672 if (unlikely(err < 0))
673 err = au_wbr_bu(sb, btop - 1);
674
675 AuDbg("b%d\n", err);
676 return err;
677}
678
679/* bottom up */
680int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop)
681{
682 int err;
683
684 err = au_wbr_bu(dentry->d_sb, btop);
685 AuDbg("b%d\n", err);
686 if (err > btop)
687 err = au_wbr_nonopq(dentry, err);
688
689 AuDbg("b%d\n", err);
690 return err;
691}
692
693static int au_wbr_copyup_bu(struct dentry *dentry)
694{
695 int err;
696 aufs_bindex_t btop;
697
698 btop = au_dbtop(dentry);
699 err = au_wbr_do_copyup_bu(dentry, btop);
700 return err;
701}
702
703/* ---------------------------------------------------------------------- */
704
705struct au_wbr_copyup_operations au_wbr_copyup_ops[] = {
706 [AuWbrCopyup_TDP] = {
707 .copyup = au_wbr_copyup_tdp
708 },
709 [AuWbrCopyup_BUP] = {
710 .copyup = au_wbr_copyup_bup
711 },
712 [AuWbrCopyup_BU] = {
713 .copyup = au_wbr_copyup_bu
714 }
715};
716
717struct au_wbr_create_operations au_wbr_create_ops[] = {
718 [AuWbrCreate_TDP] = {
719 .create = au_wbr_create_tdp
720 },
721 [AuWbrCreate_RR] = {
722 .create = au_wbr_create_rr,
723 .init = au_wbr_create_init_rr
724 },
725 [AuWbrCreate_MFS] = {
726 .create = au_wbr_create_mfs,
727 .init = au_wbr_create_init_mfs,
728 .fin = au_wbr_create_fin_mfs
729 },
730 [AuWbrCreate_MFSV] = {
731 .create = au_wbr_create_mfs,
732 .init = au_wbr_create_init_mfs,
733 .fin = au_wbr_create_fin_mfs
734 },
735 [AuWbrCreate_MFSRR] = {
736 .create = au_wbr_create_mfsrr,
737 .init = au_wbr_create_init_mfsrr,
738 .fin = au_wbr_create_fin_mfs
739 },
740 [AuWbrCreate_MFSRRV] = {
741 .create = au_wbr_create_mfsrr,
742 .init = au_wbr_create_init_mfsrr,
743 .fin = au_wbr_create_fin_mfs
744 },
745 [AuWbrCreate_PMFS] = {
746 .create = au_wbr_create_pmfs,
747 .init = au_wbr_create_init_mfs,
748 .fin = au_wbr_create_fin_mfs
749 },
750 [AuWbrCreate_PMFSV] = {
751 .create = au_wbr_create_pmfs,
752 .init = au_wbr_create_init_mfs,
753 .fin = au_wbr_create_fin_mfs
754 },
755 [AuWbrCreate_PMFSRR] = {
756 .create = au_wbr_create_pmfsrr,
757 .init = au_wbr_create_init_mfsrr,
758 .fin = au_wbr_create_fin_mfs
759 },
760 [AuWbrCreate_PMFSRRV] = {
761 .create = au_wbr_create_pmfsrr,
762 .init = au_wbr_create_init_mfsrr,
763 .fin = au_wbr_create_fin_mfs
764 }
765};