Commit | Line | Data |
---|---|---|
32a01b17 | 1 | /* |
1446b03c KB |
2 | * Copyright (c) 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
32a01b17 JH |
4 | * |
5 | * This code is derived from software donated to Berkeley by | |
6 | * Jan-Simon Pendry. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | * | |
1611db1e | 10 | * @(#)null_vfsops.c 8.2 (Berkeley) %G% |
32a01b17 | 11 | * |
11cda5c1 JH |
12 | * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 |
13 | * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $ | |
32a01b17 JH |
14 | */ |
15 | ||
16 | /* | |
11cda5c1 JH |
17 | * Null Layer |
18 | * (See null_vnops.c for a description of what this does.) | |
32a01b17 JH |
19 | */ |
20 | ||
21 | #include <sys/param.h> | |
22 | #include <sys/systm.h> | |
23 | #include <sys/time.h> | |
24 | #include <sys/types.h> | |
25 | #include <sys/vnode.h> | |
26 | #include <sys/mount.h> | |
27 | #include <sys/namei.h> | |
28 | #include <sys/malloc.h> | |
3fa2b388 | 29 | #include <miscfs/nullfs/null.h> |
32a01b17 JH |
30 | |
31 | /* | |
11cda5c1 | 32 | * Mount null layer |
32a01b17 | 33 | */ |
c8b2716f | 34 | int |
d2943a3d | 35 | nullfs_mount(mp, path, data, ndp, p) |
32a01b17 JH |
36 | struct mount *mp; |
37 | char *path; | |
38 | caddr_t data; | |
39 | struct nameidata *ndp; | |
40 | struct proc *p; | |
41 | { | |
32a01b17 | 42 | int error = 0; |
d2943a3d | 43 | struct null_args args; |
11cda5c1 | 44 | struct vnode *lowerrootvp, *vp; |
d2943a3d | 45 | struct vnode *nullm_rootvp; |
7936eee0 | 46 | struct null_mount *xmp; |
32a01b17 JH |
47 | u_int size; |
48 | ||
d2943a3d JH |
49 | #ifdef NULLFS_DIAGNOSTIC |
50 | printf("nullfs_mount(mp = %x)\n", mp); | |
32a01b17 JH |
51 | #endif |
52 | ||
53 | /* | |
54 | * Update is a no-op | |
55 | */ | |
56 | if (mp->mnt_flag & MNT_UPDATE) { | |
57 | return (EOPNOTSUPP); | |
d2943a3d | 58 | /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/ |
32a01b17 JH |
59 | } |
60 | ||
61 | /* | |
62 | * Get argument | |
63 | */ | |
d2943a3d | 64 | if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args))) |
32a01b17 JH |
65 | return (error); |
66 | ||
67 | /* | |
30969417 | 68 | * Find lower node |
32a01b17 JH |
69 | */ |
70 | NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, | |
71 | UIO_USERSPACE, args.target, p); | |
72 | if (error = namei(ndp)) | |
73 | return (error); | |
74 | ||
75 | /* | |
30969417 | 76 | * Sanity check on lower vnode |
32a01b17 | 77 | */ |
11cda5c1 | 78 | lowerrootvp = ndp->ni_vp; |
32a01b17 | 79 | |
7936eee0 JH |
80 | vrele(ndp->ni_dvp); |
81 | ndp->ni_dvp = NULL; | |
32a01b17 | 82 | |
7936eee0 | 83 | xmp = (struct null_mount *) malloc(sizeof(struct null_mount), |
32a01b17 JH |
84 | M_UFSMNT, M_WAITOK); /* XXX */ |
85 | ||
86 | /* | |
7936eee0 | 87 | * Save reference to underlying FS |
32a01b17 | 88 | */ |
7936eee0 | 89 | xmp->nullm_vfs = lowerrootvp->v_mount; |
32a01b17 JH |
90 | |
91 | /* | |
92 | * Save reference. Each mount also holds | |
93 | * a reference on the root vnode. | |
94 | */ | |
c8b2716f | 95 | error = null_node_create(mp, lowerrootvp, &vp); |
32a01b17 | 96 | /* |
30969417 | 97 | * Unlock the node (either the lower or the alias) |
32a01b17 JH |
98 | */ |
99 | VOP_UNLOCK(vp); | |
100 | /* | |
101 | * Make sure the node alias worked | |
102 | */ | |
103 | if (error) { | |
11cda5c1 | 104 | vrele(lowerrootvp); |
7936eee0 | 105 | free(xmp, M_UFSMNT); /* XXX */ |
32a01b17 JH |
106 | return (error); |
107 | } | |
108 | ||
109 | /* | |
110 | * Keep a held reference to the root vnode. | |
d2943a3d | 111 | * It is vrele'd in nullfs_unmount. |
32a01b17 | 112 | */ |
d2943a3d JH |
113 | nullm_rootvp = vp; |
114 | nullm_rootvp->v_flag |= VROOT; | |
7936eee0 | 115 | xmp->nullm_rootvp = nullm_rootvp; |
c8b2716f | 116 | if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) |
32a01b17 | 117 | mp->mnt_flag |= MNT_LOCAL; |
7936eee0 | 118 | mp->mnt_data = (qaddr_t) xmp; |
32a01b17 JH |
119 | getnewfsid(mp, MOUNT_LOFS); |
120 | ||
121 | (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); | |
122 | bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); | |
123 | (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, | |
124 | &size); | |
125 | bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); | |
d2943a3d | 126 | #ifdef NULLFS_DIAGNOSTIC |
30969417 | 127 | printf("nullfs_mount: lower %s, alias at %s\n", |
32a01b17 JH |
128 | mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); |
129 | #endif | |
130 | return (0); | |
131 | } | |
132 | ||
133 | /* | |
134 | * VFS start. Nothing needed here - the start routine | |
135 | * on the underlying filesystem will have been called | |
136 | * when that filesystem was mounted. | |
137 | */ | |
c8b2716f | 138 | int |
d2943a3d | 139 | nullfs_start(mp, flags, p) |
32a01b17 JH |
140 | struct mount *mp; |
141 | int flags; | |
142 | struct proc *p; | |
143 | { | |
144 | return (0); | |
d2943a3d | 145 | /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */ |
32a01b17 JH |
146 | } |
147 | ||
148 | /* | |
11cda5c1 | 149 | * Free reference to null layer |
32a01b17 | 150 | */ |
c8b2716f | 151 | int |
d2943a3d | 152 | nullfs_unmount(mp, mntflags, p) |
32a01b17 JH |
153 | struct mount *mp; |
154 | int mntflags; | |
155 | struct proc *p; | |
156 | { | |
d2943a3d | 157 | struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; |
32a01b17 JH |
158 | int error; |
159 | int flags = 0; | |
160 | extern int doforce; | |
161 | ||
d2943a3d JH |
162 | #ifdef NULLFS_DIAGNOSTIC |
163 | printf("nullfs_unmount(mp = %x)\n", mp); | |
32a01b17 JH |
164 | #endif |
165 | ||
166 | if (mntflags & MNT_FORCE) { | |
167 | /* lofs can never be rootfs so don't check for it */ | |
168 | if (!doforce) | |
169 | return (EINVAL); | |
170 | flags |= FORCECLOSE; | |
171 | } | |
172 | ||
173 | /* | |
174 | * Clear out buffer cache. I don't think we | |
175 | * ever get anything cached at this level at the | |
176 | * moment, but who knows... | |
177 | */ | |
c8b2716f | 178 | #if 0 |
32a01b17 JH |
179 | mntflushbuf(mp, 0); |
180 | if (mntinvalbuf(mp, 1)) | |
181 | return (EBUSY); | |
c8b2716f | 182 | #endif |
d2943a3d | 183 | if (nullm_rootvp->v_usecount > 1) |
32a01b17 | 184 | return (EBUSY); |
d2943a3d | 185 | if (error = vflush(mp, nullm_rootvp, flags)) |
32a01b17 JH |
186 | return (error); |
187 | ||
d2943a3d | 188 | #ifdef NULLFS_DIAGNOSTIC |
30969417 | 189 | vprint("alias root of lower", nullm_rootvp); |
32a01b17 JH |
190 | #endif |
191 | /* | |
192 | * Release reference on underlying root vnode | |
193 | */ | |
d2943a3d | 194 | vrele(nullm_rootvp); |
32a01b17 JH |
195 | /* |
196 | * And blow it away for future re-use | |
197 | */ | |
d2943a3d | 198 | vgone(nullm_rootvp); |
32a01b17 | 199 | /* |
d2943a3d | 200 | * Finally, throw away the null_mount structure |
32a01b17 JH |
201 | */ |
202 | free(mp->mnt_data, M_UFSMNT); /* XXX */ | |
203 | mp->mnt_data = 0; | |
204 | return 0; | |
205 | } | |
206 | ||
c8b2716f | 207 | int |
d2943a3d | 208 | nullfs_root(mp, vpp) |
32a01b17 JH |
209 | struct mount *mp; |
210 | struct vnode **vpp; | |
211 | { | |
32a01b17 JH |
212 | struct vnode *vp; |
213 | ||
d2943a3d JH |
214 | #ifdef NULLFS_DIAGNOSTIC |
215 | printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp, | |
216 | MOUNTTONULLMOUNT(mp)->nullm_rootvp, | |
c8b2716f | 217 | NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) |
32a01b17 JH |
218 | ); |
219 | #endif | |
220 | ||
221 | /* | |
222 | * Return locked reference to root. | |
223 | */ | |
d2943a3d | 224 | vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; |
32a01b17 JH |
225 | VREF(vp); |
226 | VOP_LOCK(vp); | |
227 | *vpp = vp; | |
228 | return 0; | |
229 | } | |
230 | ||
c8b2716f | 231 | int |
d2943a3d | 232 | nullfs_quotactl(mp, cmd, uid, arg, p) |
32a01b17 JH |
233 | struct mount *mp; |
234 | int cmd; | |
235 | uid_t uid; | |
236 | caddr_t arg; | |
237 | struct proc *p; | |
238 | { | |
d2943a3d | 239 | return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); |
32a01b17 JH |
240 | } |
241 | ||
c8b2716f | 242 | int |
d2943a3d | 243 | nullfs_statfs(mp, sbp, p) |
32a01b17 JH |
244 | struct mount *mp; |
245 | struct statfs *sbp; | |
246 | struct proc *p; | |
247 | { | |
248 | int error; | |
249 | struct statfs mstat; | |
250 | ||
d2943a3d JH |
251 | #ifdef NULLFS_DIAGNOSTIC |
252 | printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp, | |
253 | MOUNTTONULLMOUNT(mp)->nullm_rootvp, | |
c8b2716f | 254 | NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) |
32a01b17 JH |
255 | ); |
256 | #endif | |
257 | ||
258 | bzero(&mstat, sizeof(mstat)); | |
259 | ||
d2943a3d | 260 | error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); |
32a01b17 JH |
261 | if (error) |
262 | return (error); | |
263 | ||
264 | /* now copy across the "interesting" information and fake the rest */ | |
265 | sbp->f_type = mstat.f_type; | |
266 | sbp->f_flags = mstat.f_flags; | |
267 | sbp->f_bsize = mstat.f_bsize; | |
268 | sbp->f_iosize = mstat.f_iosize; | |
269 | sbp->f_blocks = mstat.f_blocks; | |
270 | sbp->f_bfree = mstat.f_bfree; | |
271 | sbp->f_bavail = mstat.f_bavail; | |
272 | sbp->f_files = mstat.f_files; | |
273 | sbp->f_ffree = mstat.f_ffree; | |
274 | if (sbp != &mp->mnt_stat) { | |
275 | bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); | |
276 | bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); | |
277 | bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); | |
278 | } | |
279 | return (0); | |
280 | } | |
281 | ||
c8b2716f JH |
282 | int |
283 | nullfs_sync(mp, waitfor, cred, p) | |
284 | struct mount *mp; | |
285 | int waitfor; | |
286 | struct ucred *cred; | |
287 | struct proc *p; | |
32a01b17 | 288 | { |
11cda5c1 | 289 | /* |
c8b2716f | 290 | * XXX - Assumes no data cached at null layer. |
11cda5c1 | 291 | */ |
32a01b17 JH |
292 | return (0); |
293 | } | |
294 | ||
c8b2716f JH |
295 | int |
296 | nullfs_vget(mp, ino, vpp) | |
32a01b17 | 297 | struct mount *mp; |
c8b2716f JH |
298 | ino_t ino; |
299 | struct vnode **vpp; | |
300 | { | |
301 | ||
302 | return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); | |
303 | } | |
304 | ||
305 | int | |
306 | nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) | |
307 | struct mount *mp; | |
308 | struct fid *fidp; | |
309 | struct mbuf *nam; | |
32a01b17 | 310 | struct vnode **vpp; |
c8b2716f JH |
311 | int *exflagsp; |
312 | struct ucred**credanonp; | |
32a01b17 | 313 | { |
c8b2716f JH |
314 | |
315 | return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp); | |
32a01b17 JH |
316 | } |
317 | ||
c8b2716f | 318 | int |
d2943a3d | 319 | nullfs_vptofh(vp, fhp) |
32a01b17 JH |
320 | struct vnode *vp; |
321 | struct fid *fhp; | |
322 | { | |
c8b2716f | 323 | return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp); |
32a01b17 JH |
324 | } |
325 | ||
d2943a3d JH |
326 | int nullfs_init __P((void)); |
327 | ||
328 | struct vfsops null_vfsops = { | |
329 | nullfs_mount, | |
330 | nullfs_start, | |
331 | nullfs_unmount, | |
332 | nullfs_root, | |
333 | nullfs_quotactl, | |
334 | nullfs_statfs, | |
335 | nullfs_sync, | |
c8b2716f | 336 | nullfs_vget, |
d2943a3d JH |
337 | nullfs_fhtovp, |
338 | nullfs_vptofh, | |
339 | nullfs_init, | |
32a01b17 | 340 | }; |