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 */
68static int ufs_initcount = 0;
69
70pool_cache_t ufs_direct_cache;
71
72/*
73 * Make a filesystem operational.
74 * Nothing to do at the moment.
75 */
76/* ARGSUSED */
77int
78ufs_start(struct mount *mp, int flags)
79{
80
81 return (0);
82}
83
84/*
85 * Return the root of a filesystem.
86 */
87int
88ufs_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 */
102int
103ufs_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 */
122int
123ufs_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 */
234int
235ufs_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 */
261void
262ufs_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
281void
282ufs_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 */
292void
293ufs_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