]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/umapfs/umap_vfsops.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / sys / fs / umapfs / umap_vfsops.c
1 /*-
2  * Copyright (c) 1992, 1993, 1995
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software donated to Berkeley by
6  * 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  *      @(#)umap_vfsops.c       8.8 (Berkeley) 5/14/95
33  *
34  * $FreeBSD$
35  */
36
37 /*
38  * Umap Layer
39  * (See mount_umapfs(8) for a description of this layer.)
40  */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/lock.h>
46 #include <sys/malloc.h>
47 #include <sys/mount.h>
48 #include <sys/mutex.h>
49 #include <sys/namei.h>
50 #include <sys/vnode.h>
51
52 #include <fs/umapfs/umap.h>
53
54 static MALLOC_DEFINE(M_UMAPFSMNT, "UMAP mount", "UMAP mount structure");
55
56 static vfs_omount_t             umapfs_omount;
57 static vfs_root_t               umapfs_root;
58 static vfs_quotactl_t           umapfs_quotactl;
59 static vfs_statfs_t             umapfs_statfs;
60 static vfs_unmount_t            umapfs_unmount;
61 static vfs_fhtovp_t             umapfs_fhtovp;
62 static vfs_vptofh_t             umapfs_vptofh;
63 static vfs_checkexp_t           umapfs_checkexp;
64 static vfs_vget_t               umapfs_vget;
65 static vfs_extattrctl_t umapfs_extattrctl;
66
67 /*
68  * Mount umap layer
69  */
70 static int
71 umapfs_omount(mp, path, data, ndp, td)
72         struct mount *mp;
73         char *path;
74         caddr_t data;
75         struct nameidata *ndp;
76         struct thread *td;
77 {
78         struct umap_args args;
79         struct vnode *lowerrootvp, *vp;
80         struct vnode *umapm_rootvp;
81         struct umap_mount *amp;
82         size_t size;
83         int error;
84 #ifdef DEBUG
85         int     i;
86 #endif
87
88         /*
89          * Only for root
90          */
91         if ((error = suser(td)) != 0)
92                 return (error);
93
94 #ifdef DEBUG
95         printf("umapfs_mount(mp = %p)\n", (void *)mp);
96 #endif
97
98         /*
99          * Update is a no-op
100          */
101         if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) {
102                 return (EOPNOTSUPP);
103                 /* return (VFS_MOUNT(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, path, data, ndp, td));*/
104         }
105
106         /*
107          * Get argument
108          */
109         error = copyin(data, (caddr_t)&args, sizeof(struct umap_args));
110         if (error)
111                 return (error);
112
113         /*
114          * Find lower node
115          */
116         NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
117                 UIO_USERSPACE, args.target, td);
118         error = namei(ndp);
119         if (error)
120                 return (error);
121         NDFREE(ndp, NDF_ONLY_PNBUF);
122
123         /*
124          * Sanity check on lower vnode
125          */
126         lowerrootvp = ndp->ni_vp;
127 #ifdef DEBUG
128         printf("vp = %p, check for VDIR...\n", (void *)lowerrootvp);
129 #endif
130         vrele(ndp->ni_dvp);
131         ndp->ni_dvp = 0;
132
133         if (lowerrootvp->v_type != VDIR) {
134                 vput(lowerrootvp);
135                 return (EINVAL);
136         }
137
138 #ifdef DEBUG
139         printf("mp = %p\n", (void *)mp);
140 #endif
141
142         amp = (struct umap_mount *) malloc(sizeof(struct umap_mount),
143                                 M_UMAPFSMNT, M_WAITOK); /* XXX */
144
145         /*
146          * Save reference to underlying FS
147          */
148         amp->umapm_vfs = lowerrootvp->v_mount;
149
150         /*
151          * Now copy in the number of entries and maps for umap mapping.
152          */
153         if (args.nentries > MAPFILEENTRIES || args.gnentries >
154             GMAPFILEENTRIES) {
155                 vput(lowerrootvp);
156                 free(amp, M_UMAPFSMNT);
157                 /* XXX missing error = EINVAL ? */
158                 return (error);
159         }
160
161         amp->info_nentries = args.nentries;
162         amp->info_gnentries = args.gnentries;
163         error = copyin(args.mapdata, (caddr_t)amp->info_mapdata,
164             2*sizeof(u_long)*args.nentries);
165         if (error) {
166                 free(amp, M_UMAPFSMNT);
167                 return (error);
168         }
169
170 #ifdef DEBUG
171         printf("umap_mount:nentries %d\n",args.nentries);
172         for (i = 0; i < args.nentries; i++)
173                 printf("   %lu maps to %lu\n", amp->info_mapdata[i][0],
174                     amp->info_mapdata[i][1]);
175 #endif
176
177         error = copyin(args.gmapdata, (caddr_t)amp->info_gmapdata,
178             2*sizeof(u_long)*args.gnentries);
179         if (error) {
180                 free(amp, M_UMAPFSMNT);
181                 return (error);
182         }
183
184 #ifdef DEBUG
185         printf("umap_mount:gnentries %d\n",args.gnentries);
186         for (i = 0; i < args.gnentries; i++)
187                 printf("        group %lu maps to %lu\n",
188                     amp->info_gmapdata[i][0],
189                     amp->info_gmapdata[i][1]);
190 #endif
191
192
193         /*
194          * Save reference.  Each mount also holds
195          * a reference on the root vnode.
196          */
197         error = umap_node_create(mp, lowerrootvp, &vp);
198         /*
199          * Unlock the node (either the lower or the alias)
200          */
201         VOP_UNLOCK(vp, 0, td);
202         /*
203          * Make sure the node alias worked
204          */
205         if (error) {
206                 vrele(lowerrootvp);
207                 free(amp, M_UMAPFSMNT); /* XXX */
208                 return (error);
209         }
210
211         /*
212          * Keep a held reference to the root vnode.
213          * It is vrele'd in umapfs_unmount.
214          */
215         ASSERT_VOP_LOCKED(vp, "umapfs_mount");
216         umapm_rootvp = vp;
217         umapm_rootvp->v_vflag |= VV_ROOT;
218         amp->umapm_rootvp = umapm_rootvp;
219         if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) {
220                 MNT_ILOCK(mp);
221                 mp->mnt_flag |= MNT_LOCAL;
222                 MNT_IUNLOCK(mp);
223         }
224         mp->mnt_data = (qaddr_t) amp;
225         vfs_getnewfsid(mp);
226
227         (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
228             &size);
229         bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
230         (void)umapfs_statfs(mp, &mp->mnt_stat, td);
231 #ifdef DEBUG
232         printf("umapfs_mount: lower %s, alias at %s\n",
233                 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
234 #endif
235         return (0);
236 }
237
238 /*
239  * Free reference to umap layer
240  */
241 static int
242 umapfs_unmount(mp, mntflags, td)
243         struct mount *mp;
244         int mntflags;
245         struct thread *td;
246 {
247         int error;
248         int flags = 0;
249
250 #ifdef DEBUG
251         printf("umapfs_unmount(mp = %p)\n", (void *)mp);
252 #endif
253
254         if (mntflags & MNT_FORCE)
255                 flags |= FORCECLOSE;
256
257         /*
258          * Clear out buffer cache.  I don't think we
259          * ever get anything cached at this level at the
260          * moment, but who knows...
261          */
262 #ifdef notyet
263         mntflushbuf(mp, 0);
264         if (mntinvalbuf(mp, 1))
265                 return (EBUSY);
266 #endif
267         /* There is 1 extra root vnode reference (umapm_rootvp). */
268         error = vflush(mp, 1, flags, td);
269         if (error)
270                 return (error);
271
272         /*
273          * Finally, throw away the umap_mount structure
274          */
275         free(mp->mnt_data, M_UMAPFSMNT);        /* XXX */
276         mp->mnt_data = 0;
277         return (0);
278 }
279
280 static int
281 umapfs_root(mp, flags, vpp, td)
282         struct mount *mp;
283         int flags;
284         struct vnode **vpp;
285         struct thread *td;
286 {
287         struct thread *td = curthread;  /* XXX */
288         struct vnode *vp;
289
290 #ifdef DEBUG
291         printf("umapfs_root(mp = %p, vp = %p->%p)\n",
292             (void *)mp, (void *)MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
293             (void *)UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp));
294 #endif
295
296         /*
297          * Return locked reference to root.
298          */
299         vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
300         VREF(vp);
301         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
302         *vpp = vp;
303         return (0);
304 }
305
306 static int
307 umapfs_quotactl(mp, cmd, uid, arg, td)
308         struct mount *mp;
309         int cmd;
310         uid_t uid;
311         caddr_t arg;
312         struct thread *td;
313 {
314
315         return (VFS_QUOTACTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, uid, arg, td));
316 }
317
318 static int
319 umapfs_statfs(mp, sbp, td)
320         struct mount *mp;
321         struct statfs *sbp;
322         struct thread *td;
323 {
324         int error;
325         struct statfs mstat;
326
327 #ifdef DEBUG
328         printf("umapfs_statfs(mp = %p, vp = %p->%p)\n",
329             (void *)mp, (void *)MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
330             (void *)UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp));
331 #endif
332
333         bzero(&mstat, sizeof(mstat));
334
335         error = VFS_STATFS(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, &mstat, td);
336         if (error)
337                 return (error);
338
339         /* now copy across the "interesting" information and fake the rest */
340         sbp->f_type = mstat.f_type;
341         sbp->f_flags = mstat.f_flags;
342         sbp->f_bsize = mstat.f_bsize;
343         sbp->f_iosize = mstat.f_iosize;
344         sbp->f_blocks = mstat.f_blocks;
345         sbp->f_bfree = mstat.f_bfree;
346         sbp->f_bavail = mstat.f_bavail;
347         sbp->f_files = mstat.f_files;
348         sbp->f_ffree = mstat.f_ffree;
349         return (0);
350 }
351
352 static int
353 umapfs_vget(mp, ino, flags, vpp)
354         struct mount *mp;
355         ino_t ino;
356         int flags;
357         struct vnode **vpp;
358 {
359
360         return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, flags, vpp));
361 }
362
363 static int
364 umapfs_fhtovp(mp, fidp, vpp)
365         struct mount *mp;
366         struct fid *fidp;
367         struct vnode **vpp;
368 {
369
370         return (VFS_FHTOVP(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, fidp, vpp));
371 }
372
373 static int
374 umapfs_checkexp(mp, nam, exflagsp, credanonp)
375         struct mount *mp;
376         struct sockaddr *nam;
377         int *exflagsp;
378         struct ucred **credanonp;
379 {
380
381         return (VFS_CHECKEXP(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, nam,
382                 exflagsp, credanonp));
383 }
384
385 static int
386 umapfs_vptofh(vp, fhp)
387         struct vnode *vp;
388         struct fid *fhp;
389 {
390         struct vnode *lvp;
391
392         lvp = UMAPVPTOLOWERVP(vp);
393         return (VFS_VPTOFH(lvp, fhp));
394 }
395
396 static int
397 umapfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, td)
398         struct mount *mp;
399         int cmd;
400         struct vnode *filename_vp;
401         int namespace;
402         const char *attrname;
403         struct thread *td;
404 {
405
406         return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd,
407             filename_vp, namespace, attrname, td));
408 }
409
410 static struct vfsops umap_vfsops = {
411         .vfs_checkexp =                 umapfs_checkexp,
412         .vfs_extattrctl =               umapfs_extattrctl,
413         .vfs_fhtovp =                   umapfs_fhtovp,
414         .vfs_init =                     umapfs_init,
415         .vfs_omount =                   umapfs_omount,
416         .vfs_quotactl =                 umapfs_quotactl,
417         .vfs_root =                     umapfs_root,
418         .vfs_statfs =                   umapfs_statfs,
419         .vfs_unmount =                  umapfs_unmount,
420         .vfs_vget =                     umapfs_vget,
421         .vfs_vptofh =                   umapfs_vptofh,
422 };
423
424 VFS_SET(umap_vfsops, umapfs, VFCF_LOOPBACK);