Add an argument to vfs_add_vnodeops() to specify VVF_* flags for the vop_ops
[dragonfly.git] / sys / vfs / nullfs / null_vfsops.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1992, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software donated to Berkeley by
6 * Jan-Simon Pendry.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. 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 * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94
37 *
38 * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
39 * $FreeBSD: src/sys/miscfs/nullfs/null_vfsops.c,v 1.35.2.3 2001/07/26 20:37:11 iedowse Exp $
40 * $DragonFly: src/sys/vfs/nullfs/null_vfsops.c,v 1.18 2005/09/17 07:43:12 dillon Exp $
41 */
42
43/*
44 * Null Layer
45 * (See null_vnops.c for a description of what this does.)
46 */
47
48#include <sys/param.h>
49#include <sys/systm.h>
50#include <sys/kernel.h>
51#include <sys/proc.h>
52#include <sys/malloc.h>
53#include <sys/vnode.h>
54#include <sys/mount.h>
55#include <sys/nlookup.h>
56#include "null.h"
57
58extern struct vnodeopv_entry_desc null_vnodeop_entries[];
59
60static MALLOC_DEFINE(M_NULLFSMNT, "NULLFS mount", "NULLFS mount structure");
61
62static int nullfs_fhtovp(struct mount *mp, struct fid *fidp,
63 struct vnode **vpp);
64static int nullfs_checkexp(struct mount *mp, struct sockaddr *nam,
65 int *extflagsp, struct ucred **credanonp);
66static int nullfs_mount(struct mount *mp, char *path, caddr_t data,
67 struct thread *td);
68static int nullfs_quotactl(struct mount *mp, int cmd, uid_t uid,
69 caddr_t arg, struct thread *td);
70static int nullfs_root(struct mount *mp, struct vnode **vpp);
71static int nullfs_statfs(struct mount *mp, struct statfs *sbp,
72 struct thread *td);
73static int nullfs_unmount(struct mount *mp, int mntflags, struct thread *td);
74static int nullfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
75static int nullfs_vptofh(struct vnode *vp, struct fid *fhp);
76static int nullfs_extattrctl(struct mount *mp, int cmd,
77 const char *attrname, caddr_t arg, struct thread *td);
78
79/*
80 * Mount null layer
81 */
82static int
83nullfs_mount(struct mount *mp, char *path, caddr_t data, struct thread *td)
84{
85 int error = 0;
86 struct null_args args;
87 struct vnode *lowerrootvp, *vp;
88 struct vnode *nullm_rootvp;
89 struct null_mount *xmp;
90 u_int size;
91 int isvnunlocked = 0;
92 struct nlookupdata nd;
93
94 NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
95
96 /*
97 * Update is a no-op
98 */
99 if (mp->mnt_flag & MNT_UPDATE) {
100 return (EOPNOTSUPP);
101 }
102
103 /*
104 * Get argument
105 */
106 error = copyin(data, (caddr_t)&args, sizeof(struct null_args));
107 if (error)
108 return (error);
109
110 /*
111 * Unlock lower node to avoid deadlock.
112 * (XXX) VOP_ISLOCKED is needed?
113 */
114 if ((mp->mnt_vnodecovered->v_tag == VT_NULL) &&
115 VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) {
116 VOP_UNLOCK(mp->mnt_vnodecovered, 0, td);
117 isvnunlocked = 1;
118 }
119 /*
120 * Find lower node
121 */
122 lowerrootvp = NULL;
123 error = nlookup_init(&nd, args.target, UIO_USERSPACE, NLC_FOLLOW);
124 if (error == 0)
125 error = nlookup(&nd);
126 if (error == 0) {
127 error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE,
128 &lowerrootvp);
129 }
130 nlookup_done(&nd);
131
132 /*
133 * Re-lock vnode.
134 */
135 if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered, NULL))
136 vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY, td);
137 if (error)
138 return (error);
139
140 /*
141 * Sanity check on lower vnode
142 *
143 * Check multi null mount to avoid `lock against myself' panic.
144 */
145 if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) {
146 NULLFSDEBUG("nullfs_mount: multi null mount?\n");
147 vput(lowerrootvp);
148 return (EDEADLK);
149 }
150
151 xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
152 M_NULLFSMNT, M_WAITOK); /* XXX */
153
154 /*
155 * Save reference to underlying FS
156 */
157 xmp->nullm_vfs = lowerrootvp->v_mount;
158
159 vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops,
160 null_vnodeop_entries, 0);
161
162 /*
163 * Save reference. Each mount also holds
164 * a reference on the root vnode.
165 */
166 error = null_node_create(mp, lowerrootvp, &vp);
167 /*
168 * Unlock the node (either the lower or the alias)
169 */
170 VOP_UNLOCK(vp, 0, td);
171 /*
172 * Make sure the node alias worked
173 */
174 if (error) {
175 vrele(lowerrootvp);
176 free(xmp, M_NULLFSMNT); /* XXX */
177 return (error);
178 }
179
180 /*
181 * Keep a held reference to the root vnode.
182 * It is vrele'd in nullfs_unmount.
183 */
184 nullm_rootvp = vp;
185 nullm_rootvp->v_flag |= VROOT;
186 xmp->nullm_rootvp = nullm_rootvp;
187 if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
188 mp->mnt_flag |= MNT_LOCAL;
189 mp->mnt_data = (qaddr_t) xmp;
190 vfs_getnewfsid(mp);
191
192 (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
193 &size);
194 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
195 (void)nullfs_statfs(mp, &mp->mnt_stat, td);
196 NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
197 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntfromname);
198 return (0);
199}
200
201/*
202 * Free reference to null layer
203 */
204static int
205nullfs_unmount(struct mount *mp, int mntflags, struct thread *td)
206{
207 void *mntdata;
208 int error;
209 int flags = 0;
210
211 NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp);
212
213 if (mntflags & MNT_FORCE)
214 flags |= FORCECLOSE;
215
216 /* There is 1 extra root vnode reference (nullm_rootvp). */
217 error = vflush(mp, 1, flags);
218 if (error)
219 return (error);
220
221 /*
222 * Finally, throw away the null_mount structure
223 */
224 mntdata = mp->mnt_data;
225 mp->mnt_data = 0;
226 free(mntdata, M_NULLFSMNT);
227 return 0;
228}
229
230static int
231nullfs_root(struct mount *mp, struct vnode **vpp)
232{
233 struct thread *td = curthread; /* XXX */
234 struct vnode *vp;
235
236 NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp,
237 (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
238 (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
239
240 /*
241 * Return locked reference to root.
242 */
243 vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
244 vref(vp);
245
246#ifdef NULLFS_DEBUG
247 if (VOP_ISLOCKED(vp, NULL)) {
248 Debugger("root vnode is locked.\n");
249 vrele(vp);
250 return (EDEADLK);
251 }
252#endif
253 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
254 *vpp = vp;
255 return 0;
256}
257
258static int
259nullfs_quotactl(struct mount *mp, int cmd, uid_t uid, caddr_t arg,
260 struct thread *td)
261{
262 return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, td);
263}
264
265static int
266nullfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
267{
268 int error;
269 struct statfs mstat;
270
271 NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp,
272 (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
273 (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
274
275 bzero(&mstat, sizeof(mstat));
276
277 error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, td);
278 if (error)
279 return (error);
280
281 /* now copy across the "interesting" information and fake the rest */
282 sbp->f_type = mstat.f_type;
283 sbp->f_flags = mstat.f_flags;
284 sbp->f_bsize = mstat.f_bsize;
285 sbp->f_iosize = mstat.f_iosize;
286 sbp->f_blocks = mstat.f_blocks;
287 sbp->f_bfree = mstat.f_bfree;
288 sbp->f_bavail = mstat.f_bavail;
289 sbp->f_files = mstat.f_files;
290 sbp->f_ffree = mstat.f_ffree;
291 if (sbp != &mp->mnt_stat) {
292 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
293 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
294 }
295 return (0);
296}
297
298static int
299nullfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
300{
301
302 return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
303}
304
305static int
306nullfs_fhtovp(struct mount *mp, struct fid *fidp, struct vnode **vpp)
307{
308
309 return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, vpp);
310}
311
312static int
313nullfs_checkexp(struct mount *mp, struct sockaddr *nam, int *extflagsp,
314 struct ucred **credanonp)
315{
316
317 return VFS_CHECKEXP(MOUNTTONULLMOUNT(mp)->nullm_vfs, nam,
318 extflagsp, credanonp);
319}
320
321static int
322nullfs_vptofh(struct vnode *vp, struct fid *fhp)
323{
324 return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
325}
326
327static int
328nullfs_extattrctl(struct mount *mp, int cmd, const char *attrname, caddr_t arg,
329 struct thread *td)
330{
331 return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname,
332 arg, td);
333}
334
335
336static struct vfsops null_vfsops = {
337 .vfs_mount = nullfs_mount,
338 .vfs_unmount = nullfs_unmount,
339 .vfs_root = nullfs_root,
340 .vfs_quotactl = nullfs_quotactl,
341 .vfs_statfs = nullfs_statfs,
342 .vfs_sync = vfs_stdsync,
343 .vfs_vget = nullfs_vget,
344 .vfs_fhtovp = nullfs_fhtovp,
345 .vfs_checkexp = nullfs_checkexp,
346 .vfs_vptofh = nullfs_vptofh,
347 .vfs_init = nullfs_init,
348 .vfs_uninit = nullfs_uninit,
349 .vfs_extattrctl = nullfs_extattrctl
350};
351
352VFS_SET(null_vfsops, null, VFCF_LOOPBACK);