1 | /* $NetBSD: ufs_vfsops.c,v 1.54 2015/03/17 09:39:29 hannken Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1991, 1993, 1994 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * (c) UNIX System Laboratories, Inc. |
7 | * All or some portions of this file are derived from material licensed |
8 | * to the University of California by American Telephone and Telegraph |
9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
10 | * the permission of UNIX System Laboratories, Inc. |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. |
20 | * 3. Neither the name of the University nor the names of its contributors |
21 | * may be used to endorse or promote products derived from this software |
22 | * without specific prior written permission. |
23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. |
35 | * |
36 | * @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 |
37 | */ |
38 | |
39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: ufs_vfsops.c,v 1.54 2015/03/17 09:39:29 hannken Exp $" ); |
41 | |
42 | #if defined(_KERNEL_OPT) |
43 | #include "opt_ffs.h" |
44 | #include "opt_quota.h" |
45 | #endif |
46 | |
47 | #include <sys/param.h> |
48 | #include <sys/mbuf.h> |
49 | #include <sys/mount.h> |
50 | #include <sys/proc.h> |
51 | #include <sys/buf.h> |
52 | #include <sys/vnode.h> |
53 | #include <sys/kmem.h> |
54 | #include <sys/kauth.h> |
55 | |
56 | #include <miscfs/specfs/specdev.h> |
57 | |
58 | #include <sys/quotactl.h> |
59 | #include <ufs/ufs/quota.h> |
60 | #include <ufs/ufs/inode.h> |
61 | #include <ufs/ufs/ufsmount.h> |
62 | #include <ufs/ufs/ufs_extern.h> |
63 | #ifdef UFS_DIRHASH |
64 | #include <ufs/ufs/dirhash.h> |
65 | #endif |
66 | |
67 | /* how many times ufs_init() was called */ |
68 | static int ufs_initcount = 0; |
69 | |
70 | pool_cache_t ufs_direct_cache; |
71 | |
72 | /* |
73 | * Make a filesystem operational. |
74 | * Nothing to do at the moment. |
75 | */ |
76 | /* ARGSUSED */ |
77 | int |
78 | ufs_start(struct mount *mp, int flags) |
79 | { |
80 | |
81 | return (0); |
82 | } |
83 | |
84 | /* |
85 | * Return the root of a filesystem. |
86 | */ |
87 | int |
88 | ufs_root(struct mount *mp, struct vnode **vpp) |
89 | { |
90 | struct vnode *nvp; |
91 | int error; |
92 | |
93 | if ((error = VFS_VGET(mp, (ino_t)UFS_ROOTINO, &nvp)) != 0) |
94 | return (error); |
95 | *vpp = nvp; |
96 | return (0); |
97 | } |
98 | |
99 | /* |
100 | * Look up and return a vnode/inode pair by inode number. |
101 | */ |
102 | int |
103 | ufs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) |
104 | { |
105 | int error; |
106 | |
107 | error = vcache_get(mp, &ino, sizeof(ino), vpp); |
108 | if (error) |
109 | return error; |
110 | error = vn_lock(*vpp, LK_EXCLUSIVE); |
111 | if (error) { |
112 | vrele(*vpp); |
113 | *vpp = NULL; |
114 | return error; |
115 | } |
116 | return 0; |
117 | } |
118 | |
119 | /* |
120 | * Do operations associated with quotas |
121 | */ |
122 | int |
123 | ufs_quotactl(struct mount *mp, struct quotactl_args *args) |
124 | { |
125 | |
126 | #if !defined(QUOTA) && !defined(QUOTA2) |
127 | (void) mp; |
128 | (void) args; |
129 | return (EOPNOTSUPP); |
130 | #else |
131 | struct lwp *l = curlwp; |
132 | int error; |
133 | |
134 | /* Mark the mount busy, as we're passing it to kauth(9). */ |
135 | error = vfs_busy(mp, NULL); |
136 | if (error) { |
137 | return (error); |
138 | } |
139 | mutex_enter(&mp->mnt_updating); |
140 | |
141 | error = quota_handle_cmd(mp, l, args); |
142 | |
143 | mutex_exit(&mp->mnt_updating); |
144 | vfs_unbusy(mp, false, NULL); |
145 | return (error); |
146 | #endif |
147 | } |
148 | |
149 | #if 0 |
150 | switch (cmd) { |
151 | case Q_SYNC: |
152 | break; |
153 | |
154 | case Q_GETQUOTA: |
155 | /* The user can always query about his own quota. */ |
156 | if (uid == kauth_cred_getuid(l->l_cred)) |
157 | break; |
158 | |
159 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
160 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(uid), NULL); |
161 | |
162 | break; |
163 | |
164 | case Q_QUOTAON: |
165 | case Q_QUOTAOFF: |
166 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
167 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); |
168 | |
169 | break; |
170 | |
171 | case Q_SETQUOTA: |
172 | case Q_SETUSE: |
173 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
174 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(uid), NULL); |
175 | |
176 | break; |
177 | |
178 | default: |
179 | error = EINVAL; |
180 | break; |
181 | } |
182 | |
183 | type = cmds & SUBCMDMASK; |
184 | if (!error) { |
185 | /* Only check if there was no error above. */ |
186 | if ((u_int)type >= MAXQUOTAS) |
187 | error = EINVAL; |
188 | } |
189 | |
190 | if (error) { |
191 | vfs_unbusy(mp, false, NULL); |
192 | return (error); |
193 | } |
194 | |
195 | mutex_enter(&mp->mnt_updating); |
196 | switch (cmd) { |
197 | |
198 | case Q_QUOTAON: |
199 | error = quotaon(l, mp, type, arg); |
200 | break; |
201 | |
202 | case Q_QUOTAOFF: |
203 | error = quotaoff(l, mp, type); |
204 | break; |
205 | |
206 | case Q_SETQUOTA: |
207 | error = setquota(mp, uid, type, arg); |
208 | break; |
209 | |
210 | case Q_SETUSE: |
211 | error = setuse(mp, uid, type, arg); |
212 | break; |
213 | |
214 | case Q_GETQUOTA: |
215 | error = getquota(mp, uid, type, arg); |
216 | break; |
217 | |
218 | case Q_SYNC: |
219 | error = qsync(mp); |
220 | break; |
221 | |
222 | default: |
223 | error = EINVAL; |
224 | } |
225 | mutex_exit(&mp->mnt_updating); |
226 | vfs_unbusy(mp, false, NULL); |
227 | return (error); |
228 | #endif |
229 | |
230 | /* |
231 | * This is the generic part of fhtovp called after the underlying |
232 | * filesystem has validated the file handle. |
233 | */ |
234 | int |
235 | ufs_fhtovp(struct mount *mp, struct ufid *ufhp, struct vnode **vpp) |
236 | { |
237 | struct vnode *nvp; |
238 | struct inode *ip; |
239 | int error; |
240 | |
241 | if ((error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) != 0) { |
242 | if (error == ENOENT) |
243 | error = ESTALE; |
244 | *vpp = NULLVP; |
245 | return (error); |
246 | } |
247 | ip = VTOI(nvp); |
248 | KASSERT(ip != NULL); |
249 | if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) { |
250 | vput(nvp); |
251 | *vpp = NULLVP; |
252 | return (ESTALE); |
253 | } |
254 | *vpp = nvp; |
255 | return (0); |
256 | } |
257 | |
258 | /* |
259 | * Initialize UFS filesystems, done only once. |
260 | */ |
261 | void |
262 | ufs_init(void) |
263 | { |
264 | if (ufs_initcount++ > 0) |
265 | return; |
266 | |
267 | ufs_direct_cache = pool_cache_init(sizeof(struct direct), 0, 0, 0, |
268 | "ufsdir" , NULL, IPL_NONE, NULL, NULL, NULL); |
269 | |
270 | #if defined(QUOTA) || defined(QUOTA2) |
271 | dqinit(); |
272 | #endif |
273 | #ifdef UFS_DIRHASH |
274 | ufsdirhash_init(); |
275 | #endif |
276 | #ifdef UFS_EXTATTR |
277 | ufs_extattr_init(); |
278 | #endif |
279 | } |
280 | |
281 | void |
282 | ufs_reinit(void) |
283 | { |
284 | #if defined(QUOTA) || defined(QUOTA2) |
285 | dqreinit(); |
286 | #endif |
287 | } |
288 | |
289 | /* |
290 | * Free UFS filesystem resources, done only once. |
291 | */ |
292 | void |
293 | ufs_done(void) |
294 | { |
295 | if (--ufs_initcount > 0) |
296 | return; |
297 | |
298 | #if defined(QUOTA) || defined(QUOTA2) |
299 | dqdone(); |
300 | #endif |
301 | pool_cache_destroy(ufs_direct_cache); |
302 | #ifdef UFS_DIRHASH |
303 | ufsdirhash_done(); |
304 | #endif |
305 | #ifdef UFS_EXTATTR |
306 | ufs_extattr_done(); |
307 | #endif |
308 | } |
309 | |