Merge branch 'vendor/LESS'
[dragonfly.git] / sys / vfs / nullfs / null_vnops.c
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  * 4. 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  * $FreeBSD: src/sys/miscfs/nullfs/null_vnops.c,v 1.38.2.6 2002/07/31 00:32:28 semenu Exp $
37  * $DragonFly: src/sys/vfs/nullfs/null_vnops.c,v 1.30 2008/09/17 21:44:25 dillon Exp $
38  *      ...and...
39  *      @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
40  *
41  * $FreeBSD: src/sys/miscfs/nullfs/null_vnops.c,v 1.38.2.6 2002/07/31 00:32:28 semenu Exp $
42  */
43
44 /*
45  * Null Layer
46  *
47  * (See mount_null(8) for more information.)
48  *
49  * The null layer duplicates a portion of the file system
50  * name space under a new name.  In this respect, it is
51  * similar to the loopback file system.  It differs from
52  * the loopback fs in two respects:  it is implemented using
53  * a stackable layers techniques, and its "null-node"s stack above
54  * all lower-layer vnodes, not just over directory vnodes.
55  *
56  * The null layer has two purposes.  First, it serves as a demonstration
57  * of layering by proving a layer which does nothing.  (It actually
58  * does everything the loopback file system does, which is slightly
59  * more than nothing.)  Second, the null layer can serve as a prototype
60  * layer.  Since it provides all necessary layer framework,
61  * new file system layers can be created very easily be starting
62  * with a null layer.
63  *
64  * The remainder of this man page examines the null layer as a basis
65  * for constructing new layers.
66  *
67  *
68  * INSTANTIATING NEW NULL LAYERS
69  *
70  * New null layers are created with mount_null(8).
71  * Mount_null(8) takes two arguments, the pathname
72  * of the lower vfs (target-pn) and the pathname where the null
73  * layer will appear in the namespace (alias-pn).  After
74  * the null layer is put into place, the contents
75  * of target-pn subtree will be aliased under alias-pn.
76  *
77  *
78  * OPERATION OF A NULL LAYER
79  *
80  * The null layer is the minimum file system layer,
81  * simply bypassing all possible operations to the lower layer
82  * for processing there.  The majority of its activity used to center
83  * on a so-called bypass routine, through which nullfs vnodes
84  * passed on operation to their underlying peer.
85  *
86  * However, with the current implementation nullfs doesn't have any private
87  * vnodes, rather it relies on DragonFly's namecache API. That gives a much
88  * more lightweight null layer, as namecache structures are pure data, with
89  * no private operations, so there is no need of subtle dispatching routines.
90  *
91  * Unlike the old code, this implementation is not a general skeleton overlay
92  * filesystem: to get more comprehensive overlaying, we will need vnode
93  * operation dispatch. Other overlay filesystems, like unionfs might be
94  * able to get on with a hybrid solution: overlay some vnodes, and rely
95  * on namecache API for the rest.
96  */
97  
98 #include <sys/param.h>
99 #include <sys/systm.h>
100 #include <sys/kernel.h>
101 #include <sys/sysctl.h>
102 #include <sys/vnode.h>
103 #include <sys/mount.h>
104 #include <sys/mountctl.h>
105 #include <sys/proc.h>
106 #include <sys/namei.h>
107 #include <sys/malloc.h>
108 #include <sys/buf.h>
109 #include "null.h"
110
111 static int      null_nresolve(struct vop_nresolve_args *ap);
112 static int      null_ncreate(struct vop_ncreate_args *ap);
113 static int      null_nmkdir(struct vop_nmkdir_args *ap);
114 static int      null_nmknod(struct vop_nmknod_args *ap);
115 static int      null_nlink(struct vop_nlink_args *ap);
116 static int      null_nsymlink(struct vop_nsymlink_args *ap);
117 static int      null_nwhiteout(struct vop_nwhiteout_args *ap);
118 static int      null_nremove(struct vop_nremove_args *ap);
119 static int      null_nrmdir(struct vop_nrmdir_args *ap);
120 static int      null_nrename(struct vop_nrename_args *ap);
121 static int      null_mountctl(struct vop_mountctl_args *ap);
122
123 static int
124 null_nresolve(struct vop_nresolve_args *ap)
125 {
126         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
127
128         return vop_nresolve_ap(ap);
129 }
130
131 static int
132 null_ncreate(struct vop_ncreate_args *ap)
133 {
134         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
135
136         return vop_ncreate_ap(ap);
137 }
138
139 static int
140 null_nmkdir(struct vop_nmkdir_args *ap)
141 {
142         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
143
144         return vop_nmkdir_ap(ap);
145 }
146
147 static int
148 null_nmknod(struct vop_nmknod_args *ap)
149 {
150         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
151
152         return vop_nmknod_ap(ap);
153 }
154
155 static int
156 null_nlink(struct vop_nlink_args *ap)
157 {
158         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
159
160         return vop_nlink_ap(ap);
161 }
162
163 static int
164 null_nsymlink(struct vop_nsymlink_args *ap)
165 {
166         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
167
168         return vop_nsymlink_ap(ap);
169 }
170
171 static int
172 null_nwhiteout(struct vop_nwhiteout_args *ap)
173 {
174         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
175
176         return vop_nwhiteout_ap(ap);
177 }
178
179 static int
180 null_nremove(struct vop_nremove_args *ap)
181 {
182         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
183
184         return vop_nremove_ap(ap);
185 }
186
187 static int
188 null_nrmdir(struct vop_nrmdir_args *ap)
189 {
190         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
191
192         return vop_nrmdir_ap(ap);
193 }
194
195 static int
196 null_nrename(struct vop_nrename_args *ap)
197 {
198         struct mount *lmp;
199
200         lmp = MOUNTTONULLMOUNT(ap->a_fnch->mount)->nullm_vfs;
201         if (lmp != MOUNTTONULLMOUNT(ap->a_tnch->mount)->nullm_vfs)
202                 return (EINVAL);
203
204         ap->a_head.a_ops = lmp->mnt_vn_norm_ops;
205
206         return vop_nrename_ap(ap);
207 }
208
209 static int
210 null_mountctl(struct vop_mountctl_args *ap)
211 {
212         struct mount *mp;
213         int error;
214
215         mp = ap->a_head.a_ops->head.vv_mount;
216
217         switch(ap->a_op) {
218         case MOUNTCTL_SET_EXPORT:
219                 if (ap->a_ctllen != sizeof(struct export_args))
220                         error = EINVAL;
221                 else
222                         error = nullfs_export(mp, ap->a_op, (const void *)ap->a_ctl);
223                 break;
224         case MOUNTCTL_MOUNTFLAGS:
225                 error = vop_stdmountctl(ap);
226                 break;
227         default:
228                 error = EOPNOTSUPP;
229                 break;
230         }
231         return (error);
232 #if 0
233         ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_nch->mount)->nullm_vfs->mnt_vn_norm_ops;
234
235         return vop_mountctl_ap(ap);
236 #endif
237 }
238
239 /*
240  * Global vfs data structures
241  */
242 struct vop_ops null_vnode_vops = {
243         .vop_nresolve =         null_nresolve,
244         .vop_ncreate =          null_ncreate,
245         .vop_nmkdir =           null_nmkdir,
246         .vop_nmknod =           null_nmknod,
247         .vop_nlink =            null_nlink,
248         .vop_nsymlink =         null_nsymlink,
249         .vop_nwhiteout =        null_nwhiteout,
250         .vop_nremove =          null_nremove,
251         .vop_nrmdir =           null_nrmdir,
252         .vop_nrename =          null_nrename,
253         .vop_mountctl =         null_mountctl
254 };
255