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
ufs_start(struct mount * mp,int flags)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
ufs_root(struct mount * mp,struct vnode ** vpp)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
ufs_vget(struct mount * mp,ino_t ino,struct vnode ** vpp)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
ufs_quotactl(struct mount * mp,struct quotactl_args * args)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
ufs_fhtovp(struct mount * mp,struct ufid * ufhp,struct vnode ** vpp)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
ufs_init(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
ufs_reinit(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
ufs_done(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