1 | /* $NetBSD: overlay_vfsops.c,v 1.63 2014/11/10 18:46:33 maxv Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1999, 2000 National Aeronautics & Space Administration |
5 | * All rights reserved. |
6 | * |
7 | * This software was written by William Studenmund of the |
8 | * Numerical Aerospace Simulation Facility, NASA Ames Research Center. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the National Aeronautics & Space Administration |
19 | * nor the names of its contributors may be used to endorse or promote |
20 | * products derived from this software without specific prior written |
21 | * permission. |
22 | * |
23 | * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION |
24 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
25 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
26 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- |
27 | * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
28 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
33 | * POSSIBILITY OF SUCH DAMAGE. |
34 | */ |
35 | /* |
36 | * Copyright (c) 1992, 1993, 1995 |
37 | * The Regents of the University of California. All rights reserved. |
38 | * |
39 | * This code is derived from software donated to Berkeley by |
40 | * Jan-Simon Pendry. |
41 | * |
42 | * Redistribution and use in source and binary forms, with or without |
43 | * modification, are permitted provided that the following conditions |
44 | * are met: |
45 | * 1. Redistributions of source code must retain the above copyright |
46 | * notice, this list of conditions and the following disclaimer. |
47 | * 2. Redistributions in binary form must reproduce the above copyright |
48 | * notice, this list of conditions and the following disclaimer in the |
49 | * documentation and/or other materials provided with the distribution. |
50 | * 3. Neither the name of the University nor the names of its contributors |
51 | * may be used to endorse or promote products derived from this software |
52 | * without specific prior written permission. |
53 | * |
54 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
55 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
56 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
57 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
58 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
59 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
60 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
61 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
62 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
63 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
64 | * SUCH DAMAGE. |
65 | * |
66 | * from: Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp |
67 | * from: @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 |
68 | * @(#)null_vfsops.c 8.7 (Berkeley) 5/14/95 |
69 | */ |
70 | |
71 | /* |
72 | * Overlay Layer |
73 | * (See overlay_vnops.c for a description of what this does.) |
74 | */ |
75 | |
76 | #include <sys/cdefs.h> |
77 | __KERNEL_RCSID(0, "$NetBSD: overlay_vfsops.c,v 1.63 2014/11/10 18:46:33 maxv Exp $" ); |
78 | |
79 | #include <sys/param.h> |
80 | #include <sys/systm.h> |
81 | #include <sys/sysctl.h> |
82 | #include <sys/time.h> |
83 | #include <sys/proc.h> |
84 | #include <sys/vnode.h> |
85 | #include <sys/mount.h> |
86 | #include <sys/namei.h> |
87 | #include <sys/module.h> |
88 | #include <miscfs/overlay/overlay.h> |
89 | #include <miscfs/genfs/layer_extern.h> |
90 | |
91 | MODULE(MODULE_CLASS_VFS, overlay, "layerfs" ); |
92 | |
93 | VFS_PROTOS(ov); |
94 | |
95 | static struct sysctllog *overlay_sysctl_log; |
96 | |
97 | #define NOVERLAYNODECACHE 16 |
98 | |
99 | /* |
100 | * Mount overlay layer |
101 | */ |
102 | int |
103 | ov_mount(struct mount *mp, const char *path, void *data, size_t *data_len) |
104 | { |
105 | struct lwp *l = curlwp; |
106 | int error = 0; |
107 | struct overlay_args *args = data; |
108 | struct vnode *lowerrootvp, *vp; |
109 | struct overlay_mount *nmp; |
110 | struct layer_mount *lmp; |
111 | |
112 | #ifdef OVERLAYFS_DIAGNOSTIC |
113 | printf("ov_mount(mp = %p)\n" , mp); |
114 | #endif |
115 | |
116 | if (args == NULL) |
117 | return EINVAL; |
118 | if (*data_len < sizeof *args) |
119 | return EINVAL; |
120 | |
121 | if (mp->mnt_flag & MNT_GETARGS) { |
122 | lmp = MOUNTTOLAYERMOUNT(mp); |
123 | if (lmp == NULL) |
124 | return EIO; |
125 | args->la.target = NULL; |
126 | *data_len = sizeof *args; |
127 | return 0; |
128 | } |
129 | |
130 | /* |
131 | * Update is not supported |
132 | */ |
133 | if (mp->mnt_flag & MNT_UPDATE) |
134 | return EOPNOTSUPP; |
135 | |
136 | /* |
137 | * Find lower node |
138 | */ |
139 | lowerrootvp = mp->mnt_vnodecovered; |
140 | vref(lowerrootvp); |
141 | if ((error = vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY))) { |
142 | vrele(lowerrootvp); |
143 | return (error); |
144 | } |
145 | |
146 | /* |
147 | * First cut at fixing up upper mount point |
148 | */ |
149 | nmp = kmem_zalloc(sizeof(struct overlay_mount), KM_SLEEP); |
150 | |
151 | mp->mnt_data = nmp; |
152 | nmp->ovm_vfs = lowerrootvp->v_mount; |
153 | if (nmp->ovm_vfs->mnt_flag & MNT_LOCAL) |
154 | mp->mnt_flag |= MNT_LOCAL; |
155 | |
156 | /* |
157 | * Make sure that the mount point is sufficiently initialized |
158 | * that the node create call will work. |
159 | */ |
160 | vfs_getnewfsid(mp); |
161 | |
162 | nmp->ovm_size = sizeof (struct overlay_node); |
163 | nmp->ovm_tag = VT_OVERLAY; |
164 | nmp->ovm_bypass = layer_bypass; |
165 | nmp->ovm_vnodeop_p = overlay_vnodeop_p; |
166 | |
167 | /* |
168 | * Fix up overlay node for root vnode |
169 | */ |
170 | VOP_UNLOCK(lowerrootvp); |
171 | error = layer_node_create(mp, lowerrootvp, &vp); |
172 | /* |
173 | * Make sure the fixup worked |
174 | */ |
175 | if (error) { |
176 | vrele(lowerrootvp); |
177 | kmem_free(nmp, sizeof(struct overlay_mount)); |
178 | return error; |
179 | } |
180 | |
181 | /* |
182 | * Keep a held reference to the root vnode. |
183 | * It is vrele'd in ov_unmount. |
184 | */ |
185 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
186 | vp->v_vflag |= VV_ROOT; |
187 | nmp->ovm_rootvp = vp; |
188 | VOP_UNLOCK(vp); |
189 | |
190 | error = set_statvfs_info(path, UIO_USERSPACE, args->la.target, |
191 | UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); |
192 | #ifdef OVERLAYFS_DIAGNOSTIC |
193 | printf("ov_mount: lower %s, alias at %s\n" , |
194 | mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); |
195 | #endif |
196 | return error; |
197 | } |
198 | |
199 | /* |
200 | * Free reference to overlay layer |
201 | */ |
202 | int |
203 | ov_unmount(struct mount *mp, int mntflags) |
204 | { |
205 | struct vnode *overlay_rootvp = MOUNTTOOVERLAYMOUNT(mp)->ovm_rootvp; |
206 | struct overlay_mount *omp; |
207 | int error; |
208 | int flags = 0; |
209 | |
210 | #ifdef OVERLAYFS_DIAGNOSTIC |
211 | printf("ov_unmount(mp = %p)\n" , mp); |
212 | #endif |
213 | |
214 | if (mntflags & MNT_FORCE) |
215 | flags |= FORCECLOSE; |
216 | |
217 | if (overlay_rootvp->v_usecount > 1 && (mntflags & MNT_FORCE) == 0) |
218 | return (EBUSY); |
219 | if ((error = vflush(mp, overlay_rootvp, flags)) != 0) |
220 | return (error); |
221 | |
222 | #ifdef OVERLAYFS_DIAGNOSTIC |
223 | vprint("alias root of lower" , overlay_rootvp); |
224 | #endif |
225 | /* |
226 | * Blow it away for future re-use |
227 | */ |
228 | vgone(overlay_rootvp); |
229 | /* |
230 | * Finally, throw away the overlay_mount structure |
231 | */ |
232 | omp = mp->mnt_data; |
233 | kmem_free(omp, sizeof(struct overlay_mount)); |
234 | mp->mnt_data = NULL; |
235 | return 0; |
236 | } |
237 | |
238 | extern const struct vnodeopv_desc overlay_vnodeop_opv_desc; |
239 | |
240 | const struct vnodeopv_desc * const ov_vnodeopv_descs[] = { |
241 | &overlay_vnodeop_opv_desc, |
242 | NULL, |
243 | }; |
244 | |
245 | struct vfsops overlay_vfsops = { |
246 | .vfs_name = MOUNT_OVERLAY, |
247 | .vfs_min_mount_data = sizeof (struct overlay_args), |
248 | .vfs_mount = ov_mount, |
249 | .vfs_start = layerfs_start, |
250 | .vfs_unmount = ov_unmount, |
251 | .vfs_root = layerfs_root, |
252 | .vfs_quotactl = layerfs_quotactl, |
253 | .vfs_statvfs = layerfs_statvfs, |
254 | .vfs_sync = layerfs_sync, |
255 | .vfs_loadvnode = layerfs_loadvnode, |
256 | .vfs_vget = layerfs_vget, |
257 | .vfs_fhtovp = layerfs_fhtovp, |
258 | .vfs_vptofh = layerfs_vptofh, |
259 | .vfs_init = layerfs_init, |
260 | .vfs_done = layerfs_done, |
261 | .vfs_snapshot = layerfs_snapshot, |
262 | .vfs_extattrctl = vfs_stdextattrctl, |
263 | .vfs_suspendctl = (void *)eopnotsupp, |
264 | .vfs_renamelock_enter = layerfs_renamelock_enter, |
265 | .vfs_renamelock_exit = layerfs_renamelock_exit, |
266 | .vfs_fsync = (void *)eopnotsupp, |
267 | .vfs_opv_descs = ov_vnodeopv_descs |
268 | }; |
269 | |
270 | static int |
271 | overlay_modcmd(modcmd_t cmd, void *arg) |
272 | { |
273 | int error; |
274 | |
275 | switch (cmd) { |
276 | case MODULE_CMD_INIT: |
277 | error = vfs_attach(&overlay_vfsops); |
278 | if (error != 0) |
279 | break; |
280 | sysctl_createv(&overlay_sysctl_log, 0, NULL, NULL, |
281 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "overlay" , |
282 | SYSCTL_DESCR("Overlay file system" ), |
283 | NULL, 0, NULL, 0, |
284 | CTL_VFS, CTL_CREATE, CTL_EOL); |
285 | break; |
286 | case MODULE_CMD_FINI: |
287 | error = vfs_detach(&overlay_vfsops); |
288 | if (error != 0) |
289 | break; |
290 | sysctl_teardown(&overlay_sysctl_log); |
291 | break; |
292 | default: |
293 | error = ENOTTY; |
294 | break; |
295 | } |
296 | |
297 | return (error); |
298 | } |
299 | |