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