1 | /* $NetBSD: vfs_hooks.c,v 1.6 2009/03/15 17:14:40 cegger Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2005 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Julio M. Merino Vidal. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * VFS hooks. |
34 | */ |
35 | |
36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: vfs_hooks.c,v 1.6 2009/03/15 17:14:40 cegger Exp $" ); |
38 | |
39 | #include <sys/param.h> |
40 | #include <sys/queue.h> |
41 | #include <sys/mount.h> |
42 | #include <sys/mutex.h> |
43 | |
44 | LIST_HEAD(vfs_hooks_head, vfs_hooks) vfs_hooks_head = |
45 | LIST_HEAD_INITIALIZER(vfs_hooks_head); |
46 | |
47 | kmutex_t vfs_hooks_lock; |
48 | |
49 | void |
50 | vfs_hooks_init(void) |
51 | { |
52 | |
53 | mutex_init(&vfs_hooks_lock, MUTEX_DEFAULT, IPL_NONE); |
54 | } |
55 | |
56 | int |
57 | vfs_hooks_attach(struct vfs_hooks *vfs_hooks) |
58 | { |
59 | |
60 | mutex_enter(&vfs_hooks_lock); |
61 | LIST_INSERT_HEAD(&vfs_hooks_head, vfs_hooks, vfs_hooks_list); |
62 | mutex_exit(&vfs_hooks_lock); |
63 | |
64 | return (0); |
65 | } |
66 | |
67 | int |
68 | vfs_hooks_detach(struct vfs_hooks *vfs_hooks) |
69 | { |
70 | struct vfs_hooks *hp; |
71 | int ret = 0; |
72 | |
73 | mutex_enter(&vfs_hooks_lock); |
74 | LIST_FOREACH(hp, &vfs_hooks_head, vfs_hooks_list) { |
75 | if (hp == vfs_hooks) { |
76 | LIST_REMOVE(hp, vfs_hooks_list); |
77 | break; |
78 | } |
79 | } |
80 | if (hp == NULL) |
81 | ret = ESRCH; |
82 | mutex_exit(&vfs_hooks_lock); |
83 | |
84 | return (ret); |
85 | } |
86 | |
87 | /* |
88 | * Macro to be used in one of the vfs_hooks_* function for hooks that |
89 | * return an error code. Calls will stop as soon as one of the hooks |
90 | * fails. |
91 | */ |
92 | #define VFS_HOOKS_W_ERROR(func, fargs, hook, hargs) \ |
93 | int \ |
94 | func fargs \ |
95 | { \ |
96 | int error; \ |
97 | struct vfs_hooks *hp; \ |
98 | \ |
99 | error = EJUSTRETURN; \ |
100 | \ |
101 | mutex_enter(&vfs_hooks_lock); \ |
102 | LIST_FOREACH(hp, &vfs_hooks_head, vfs_hooks_list) { \ |
103 | if (hp-> hook != NULL) { \ |
104 | error = hp-> hook hargs; \ |
105 | if (error != 0) \ |
106 | break; \ |
107 | } \ |
108 | } \ |
109 | mutex_exit(&vfs_hooks_lock); \ |
110 | \ |
111 | return error; \ |
112 | } |
113 | |
114 | /* |
115 | * Macro to be used in one of the vfs_hooks_* function for hooks that |
116 | * do not return any error code. All hooks will be executed |
117 | * unconditionally. |
118 | */ |
119 | #define VFS_HOOKS_WO_ERROR(func, fargs, hook, hargs) \ |
120 | void \ |
121 | func fargs \ |
122 | { \ |
123 | struct vfs_hooks *hp; \ |
124 | \ |
125 | mutex_enter(&vfs_hooks_lock); \ |
126 | LIST_FOREACH(hp, &vfs_hooks_head, vfs_hooks_list) { \ |
127 | if (hp-> hook != NULL) \ |
128 | hp-> hook hargs; \ |
129 | } \ |
130 | mutex_exit(&vfs_hooks_lock); \ |
131 | } |
132 | |
133 | /* |
134 | * Routines to iterate over VFS hooks lists and execute them. |
135 | */ |
136 | |
137 | VFS_HOOKS_WO_ERROR(vfs_hooks_unmount, (struct mount *mp), vh_unmount, (mp)); |
138 | VFS_HOOKS_W_ERROR(vfs_hooks_reexport, (struct mount *mp, const char *path, void *data), vh_reexport, (mp, path, data)); |
139 | |