xref: /dragonfly/sys/vfs/nullfs/null_vnops.c (revision 92fe556d)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * John Heidemann of the UCLA Ficus project.
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. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)null_vnops.c	8.6 (Berkeley) 5/27/95
33  *
34  * Ancestors:
35  *	@(#)lofs_vnops.c	1.2 (Berkeley) 6/18/92
36  *	@(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
37  *
38  * $FreeBSD: src/sys/miscfs/nullfs/null_vnops.c,v 1.38.2.6 2002/07/31 00:32:28 semenu Exp $
39  */
40 
41 /*
42  * Null Layer
43  *
44  * (See mount_null(8) for more information.)
45  *
46  * The null layer duplicates a portion of the file system
47  * name space under a new name.  In this respect, it is
48  * similar to the loopback file system.  It differs from
49  * the loopback fs in two respects:  it is implemented using
50  * a stackable layers techniques, and its "null-node"s stack above
51  * all lower-layer vnodes, not just over directory vnodes.
52  *
53  * The null layer has two purposes.  First, it serves as a demonstration
54  * of layering by proving a layer which does nothing.  (It actually
55  * does everything the loopback file system does, which is slightly
56  * more than nothing.)  Second, the null layer can serve as a prototype
57  * layer.  Since it provides all necessary layer framework,
58  * new file system layers can be created very easily be starting
59  * with a null layer.
60  *
61  * The remainder of this man page examines the null layer as a basis
62  * for constructing new layers.
63  *
64  *
65  * INSTANTIATING NEW NULL LAYERS
66  *
67  * New null layers are created with mount_null(8).
68  * Mount_null(8) takes two arguments, the pathname
69  * of the lower vfs (target-pn) and the pathname where the null
70  * layer will appear in the namespace (alias-pn).  After
71  * the null layer is put into place, the contents
72  * of target-pn subtree will be aliased under alias-pn.
73  *
74  *
75  * OPERATION OF A NULL LAYER
76  *
77  * The null layer is the minimum file system layer,
78  * simply bypassing all possible operations to the lower layer
79  * for processing there.  The majority of its activity used to center
80  * on a so-called bypass routine, through which nullfs vnodes
81  * passed on operation to their underlying peer.
82  *
83  * However, with the current implementation nullfs doesn't have any private
84  * vnodes, rather it relies on DragonFly's namecache API. That gives a much
85  * more lightweight null layer, as namecache structures are pure data, with
86  * no private operations, so there is no need of subtle dispatching routines.
87  *
88  * Unlike the old code, this implementation is not a general skeleton overlay
89  * filesystem: to get more comprehensive overlaying, we will need vnode
90  * operation dispatch. Other overlay filesystems might be
91  * able to get on with a hybrid solution: overlay some vnodes, and rely
92  * on namecache API for the rest.
93  */
94 
95 #include <sys/param.h>
96 #include <sys/systm.h>
97 #include <sys/kernel.h>
98 #include <sys/sysctl.h>
99 #include <sys/vnode.h>
100 #include <sys/mount.h>
101 #include <sys/mountctl.h>
102 #include <sys/proc.h>
103 #include <sys/malloc.h>
104 #include <sys/buf.h>
105 #include "null.h"
106 
107 static int	null_nresolve(struct vop_nresolve_args *ap);
108 static int	null_ncreate(struct vop_ncreate_args *ap);
109 static int	null_nmkdir(struct vop_nmkdir_args *ap);
110 static int	null_nmknod(struct vop_nmknod_args *ap);
111 static int	null_nlink(struct vop_nlink_args *ap);
112 static int	null_nsymlink(struct vop_nsymlink_args *ap);
113 static int	null_nwhiteout(struct vop_nwhiteout_args *ap);
114 static int	null_nremove(struct vop_nremove_args *ap);
115 static int	null_nrmdir(struct vop_nrmdir_args *ap);
116 static int	null_nrename(struct vop_nrename_args *ap);
117 static int	null_mountctl(struct vop_mountctl_args *ap);
118 
119 static int
120 null_nresolve(struct vop_nresolve_args *ap)
121 {
122 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
123 
124 	return vop_nresolve_ap(ap);
125 }
126 
127 static int
128 null_ncreate(struct vop_ncreate_args *ap)
129 {
130 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
131 
132 	return vop_ncreate_ap(ap);
133 }
134 
135 static int
136 null_nmkdir(struct vop_nmkdir_args *ap)
137 {
138 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
139 
140 	return vop_nmkdir_ap(ap);
141 }
142 
143 static int
144 null_nmknod(struct vop_nmknod_args *ap)
145 {
146 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
147 
148 	return vop_nmknod_ap(ap);
149 }
150 
151 static int
152 null_nlink(struct vop_nlink_args *ap)
153 {
154 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
155 
156 	return vop_nlink_ap(ap);
157 }
158 
159 static int
160 null_nsymlink(struct vop_nsymlink_args *ap)
161 {
162 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
163 
164 	return vop_nsymlink_ap(ap);
165 }
166 
167 static int
168 null_nwhiteout(struct vop_nwhiteout_args *ap)
169 {
170 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
171 
172 	return vop_nwhiteout_ap(ap);
173 }
174 
175 static int
176 null_nremove(struct vop_nremove_args *ap)
177 {
178 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
179 
180 	return vop_nremove_ap(ap);
181 }
182 
183 static int
184 null_nrmdir(struct vop_nrmdir_args *ap)
185 {
186 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
187 
188 	return vop_nrmdir_ap(ap);
189 }
190 
191 static int
192 null_nrename(struct vop_nrename_args *ap)
193 {
194 	struct mount *lmp;
195 
196 	lmp = MOUNTTONULLMOUNT(ap->a_fnch->mount)->nullm_vfs;
197 	if (lmp != MOUNTTONULLMOUNT(ap->a_tnch->mount)->nullm_vfs)
198 		return (EINVAL);
199 
200 	ap->a_head.a_ops = lmp->mnt_vn_norm_ops;
201 
202 	return vop_nrename_ap(ap);
203 }
204 
205 static int
206 null_mountctl(struct vop_mountctl_args *ap)
207 {
208 	struct mount *mp;
209 	int error;
210 
211 	mp = ap->a_head.a_ops->head.vv_mount;
212 
213 	switch(ap->a_op) {
214 	case MOUNTCTL_SET_EXPORT:
215 		if (ap->a_ctllen != sizeof(struct export_args))
216 			error = EINVAL;
217 		else
218 			error = nullfs_export(mp, ap->a_op, (const void *)ap->a_ctl);
219 		break;
220 	case MOUNTCTL_MOUNTFLAGS:
221 		error = vop_stdmountctl(ap);
222 		break;
223 	default:
224 		error = EOPNOTSUPP;
225 		break;
226 	}
227 	return (error);
228 #if 0
229 	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
230 
231 	return vop_mountctl_ap(ap);
232 #endif
233 }
234 
235 /*
236  * Global vfs data structures
237  */
238 struct vop_ops null_vnode_vops = {
239 	.vop_nresolve =		null_nresolve,
240 	.vop_ncreate =		null_ncreate,
241 	.vop_nmkdir =		null_nmkdir,
242 	.vop_nmknod =		null_nmknod,
243 	.vop_nlink =		null_nlink,
244 	.vop_nsymlink =		null_nsymlink,
245 	.vop_nwhiteout =	null_nwhiteout,
246 	.vop_nremove =		null_nremove,
247 	.vop_nrmdir =		null_nrmdir,
248 	.vop_nrename =		null_nrename,
249 	.vop_mountctl =		null_mountctl
250 };
251 
252