]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/fs/hpfs/hpfs_vfsops.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / fs / hpfs / hpfs_vfsops.c
1 /*-
2  * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/namei.h>
33 #include <sys/conf.h>
34 #include <sys/proc.h>
35 #include <sys/kernel.h>
36 #include <sys/vnode.h>
37 #include <sys/mount.h>
38 #include <sys/bio.h>
39 #include <sys/buf.h>
40 #include <sys/fcntl.h>
41 #include <sys/malloc.h>
42
43 #include <geom/geom.h>
44 #include <geom/geom_vfs.h>
45
46 #include <vm/vm.h>
47 #include <vm/vm_param.h>
48 #include <vm/vm_page.h>
49 #include <vm/vm_object.h>
50 #include <vm/vm_extern.h>
51
52 #include <fs/hpfs/hpfs.h>
53 #include <fs/hpfs/hpfsmount.h>
54 #include <fs/hpfs/hpfs_subr.h>
55
56 MALLOC_DEFINE(M_HPFSMNT, "hpfs_mount", "HPFS mount structure");
57 MALLOC_DEFINE(M_HPFSNO, "hpfs_node", "HPFS node structure");
58
59 struct sockaddr;
60
61 static int      hpfs_mountfs(register struct vnode *, struct mount *, 
62                                   struct thread *);
63
64 static vfs_fhtovp_t     hpfs_fhtovp;
65 static vfs_vget_t       hpfs_vget;
66 static vfs_cmount_t     hpfs_cmount;
67 static vfs_mount_t      hpfs_mount;
68 static vfs_root_t       hpfs_root;
69 static vfs_statfs_t     hpfs_statfs;
70 static vfs_unmount_t    hpfs_unmount;
71
72 static int
73 hpfs_cmount ( 
74         struct mntarg *ma,
75         void *data,
76         int flags)
77 {
78         struct hpfs_args args;
79         int error;
80
81         error = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args));
82         if (error)
83                 return (error);
84
85         ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN);
86         ma = mount_arg(ma, "export", &args.export, sizeof args.export);
87         ma = mount_argf(ma, "uid", "%d", args.uid);
88         ma = mount_argf(ma, "gid", "%d", args.gid);
89         ma = mount_argf(ma, "mode", "%d", args.mode);
90         if (args.flags & HPFSMNT_TABLES) {
91                 ma = mount_arg(ma, "d2u", args.d2u, sizeof args.d2u);
92                 ma = mount_arg(ma, "u2d", args.u2d, sizeof args.u2d);
93         }
94
95         error = kernel_mount(ma, flags);
96
97         return (error);
98 }
99
100 static const char *hpfs_opts[] = {
101         "from", "export", "uid", "gid", "mode", "d2u", "u2d", NULL
102 };
103
104 static int
105 hpfs_mount (struct mount *mp)
106 {
107         int             err = 0, error;
108         struct vnode    *devvp;
109         struct thread *td;
110         struct nameidata ndp;
111         struct export_args export;
112         char *from;
113
114         td = curthread;
115         dprintf(("hpfs_omount():\n"));
116         /*
117          ***
118          * Mounting non-root filesystem or updating a filesystem
119          ***
120          */
121         if (vfs_filteropt(mp->mnt_optnew, hpfs_opts))
122                 return (EINVAL);
123
124         from = vfs_getopts(mp->mnt_optnew, "from", &error);
125         if (error)
126                 return (error);
127
128         /*
129          * If updating, check whether changing from read-only to
130          * read/write; if there is no device name, that's all we do.
131          */
132         if (mp->mnt_flag & MNT_UPDATE) {
133                 dprintf(("hpfs_omount: MNT_UPDATE: "));
134
135                 if (from == NULL) {
136                         error = vfs_copyopt(mp->mnt_optnew, "export",
137                             &export, sizeof export);
138                         if (error)
139                                 return (error);
140                         dprintf(("export 0x%x\n",args.export.ex_flags));
141                         err = vfs_export(mp, &export);
142                         if (err) {
143                                 printf("hpfs_omount: vfs_export failed %d\n",
144                                         err);
145                         }
146                         goto success;
147                 } else {
148                         dprintf(("name [FAILED]\n"));
149                         err = EINVAL;
150                         goto success;
151                 }
152                 dprintf(("\n"));
153         }
154
155         /*
156          * Not an update, or updating the name: look up the name
157          * and verify that it refers to a sensible block device.
158          */
159         NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td);
160         err = namei(&ndp);
161         if (err) {
162                 /* can't get devvp!*/
163                 goto error_1;
164         }
165
166         devvp = ndp.ni_vp;
167
168         if (!vn_isdisk(devvp, &err)) {
169                 vput(devvp);
170                 return (err);
171         }
172
173         /*
174          ********************
175          * NEW MOUNT
176          ********************
177          */
178
179         /*
180          * Since this is a new mount, we want the names for
181          * the device and the mount point copied in.  If an
182          * error occurs, the mountpoint is discarded by the
183          * upper level code.  Note that vfs_omount() handles
184          * copying the mountpoint f_mntonname for us, so we
185          * don't have to do it here unless we want to set it
186          * to something other than "path" for some rason.
187          */
188         /* Save "mounted from" info for mount point (NULL pad)*/
189         vfs_mountedfrom(mp, from);
190
191         err = hpfs_mountfs(devvp, mp, td);
192         if (err) {
193                 vrele(devvp);
194                 goto error_1;
195         }
196
197         goto success;
198
199 error_1:        /* no state to back out*/
200         /* XXX: Missing NDFREE(&ndp, ...) */
201
202 success:
203         return( err);
204 }
205
206 /*
207  * Common code for mount and mountroot
208  */
209 int
210 hpfs_mountfs(devvp, mp, td)
211         register struct vnode *devvp;
212         struct mount *mp;
213         struct thread *td;
214 {
215         int error, ronly, v;
216         struct sublock *sup;
217         struct spblock *spp;
218         struct hpfsmount *hpmp;
219         struct buf *bp = NULL;
220         struct vnode *vp;
221         struct cdev *dev = devvp->v_rdev;
222         struct g_consumer *cp;
223         struct bufobj *bo;
224
225         if (mp->mnt_flag & MNT_ROOTFS)
226                 return (EOPNOTSUPP);
227         dprintf(("hpfs_mountfs():\n"));
228         ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
229         /* XXX: use VOP_ACCESS to check FS perms */
230         DROP_GIANT();
231         g_topology_lock();
232         error = g_vfs_open(devvp, &cp, "hpfs", ronly ? 0 : 1);
233         g_topology_unlock();
234         PICKUP_GIANT();
235         VOP_UNLOCK(devvp, 0);
236         if (error)
237                 return (error);
238
239         bo = &devvp->v_bufobj;
240         bo->bo_private = cp;
241         bo->bo_ops = g_vfs_bufops;
242
243         /*
244          * Do actual mount
245          */
246         hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK | M_ZERO);
247
248         hpmp->hpm_cp = cp;
249         hpmp->hpm_bo = bo;
250
251         /* Read in SuperBlock */
252         error = bread(devvp, SUBLOCK, SUSIZE, NOCRED, &bp);
253         if (error)
254                 goto failed;
255         bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock));
256         brelse(bp); bp = NULL;
257
258         /* Read in SpareBlock */
259         error = bread(devvp, SPBLOCK, SPSIZE, NOCRED, &bp);
260         if (error)
261                 goto failed;
262         bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock));
263         brelse(bp); bp = NULL;
264
265         sup = &hpmp->hpm_su;
266         spp = &hpmp->hpm_sp;
267
268         /* Check magic */
269         if (sup->su_magic != SU_MAGIC) {
270                 printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n");
271                 error = EINVAL;
272                 goto failed;
273         }
274         if (spp->sp_magic != SP_MAGIC) {
275                 printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n");
276                 error = EINVAL;
277                 goto failed;
278         }
279
280         mp->mnt_data = hpmp;
281         hpmp->hpm_devvp = devvp;
282         hpmp->hpm_dev = devvp->v_rdev;
283         hpmp->hpm_mp = mp;
284         if (1 == vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v))
285                 hpmp->hpm_uid = v;
286         if (1 == vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v))
287                 hpmp->hpm_gid = v;
288         if (1 == vfs_scanopt(mp->mnt_optnew, "mode", "%d", &v))
289                 hpmp->hpm_mode = v;
290
291         error = hpfs_bminit(hpmp);
292         if (error)
293                 goto failed;
294
295         error = hpfs_cpinit(mp, hpmp);
296         if (error) {
297                 hpfs_bmdeinit(hpmp);
298                 goto failed;
299         }
300
301         error = hpfs_root(mp, LK_EXCLUSIVE, &vp);
302         if (error) {
303                 hpfs_cpdeinit(hpmp);
304                 hpfs_bmdeinit(hpmp);
305                 goto failed;
306         }
307
308         vput(vp);
309
310         mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev);
311         mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
312         mp->mnt_maxsymlinklen = 0;
313         MNT_ILOCK(mp);
314         mp->mnt_flag |= MNT_LOCAL;
315         MNT_IUNLOCK(mp);
316         return (0);
317
318 failed:
319         if (bp)
320                 brelse (bp);
321         mp->mnt_data = NULL;
322         DROP_GIANT();
323         g_topology_lock();
324         g_vfs_close(cp);
325         g_topology_unlock();
326         PICKUP_GIANT();
327         return (error);
328 }
329
330 static int
331 hpfs_unmount( 
332         struct mount *mp,
333         int mntflags)
334 {
335         int error, flags;
336         register struct hpfsmount *hpmp = VFSTOHPFS(mp);
337
338         dprintf(("hpfs_unmount():\n"));
339
340         flags = 0;
341         if(mntflags & MNT_FORCE)
342                 flags |= FORCECLOSE;
343
344         dprintf(("hpfs_unmount: vflushing...\n"));
345         
346         error = vflush(mp, 0, flags, curthread);
347         if (error) {
348                 printf("hpfs_unmount: vflush failed: %d\n",error);
349                 return (error);
350         }
351
352         vinvalbuf(hpmp->hpm_devvp, V_SAVE, 0, 0);
353         DROP_GIANT();
354         g_topology_lock();
355         g_vfs_close(hpmp->hpm_cp);
356         g_topology_unlock();
357         PICKUP_GIANT();
358         vrele(hpmp->hpm_devvp);
359
360         dprintf(("hpfs_umount: freeing memory...\n"));
361         hpfs_cpdeinit(hpmp);
362         hpfs_bmdeinit(hpmp);
363         mp->mnt_data = NULL;
364         MNT_ILOCK(mp);
365         mp->mnt_flag &= ~MNT_LOCAL;
366         MNT_IUNLOCK(mp);
367         free(hpmp, M_HPFSMNT);
368
369         return (0);
370 }
371
372 static int
373 hpfs_root(
374         struct mount *mp,
375         int flags,
376         struct vnode **vpp)
377 {
378         int error = 0;
379         struct hpfsmount *hpmp = VFSTOHPFS(mp);
380
381         dprintf(("hpfs_root():\n"));
382         error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, LK_EXCLUSIVE, vpp);
383         if(error) {
384                 printf("hpfs_root: VFS_VGET failed: %d\n",error);
385                 return (error);
386         }
387
388         return (error);
389 }
390
391 static int
392 hpfs_statfs(
393         struct mount *mp,
394         struct statfs *sbp)
395 {
396         struct hpfsmount *hpmp = VFSTOHPFS(mp);
397
398         dprintf(("hpfs_statfs(): HPFS%d.%d\n",
399                 hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver));
400
401         sbp->f_type = mp->mnt_vfc->vfc_typenum;
402         sbp->f_bsize = DEV_BSIZE;
403         sbp->f_iosize = DEV_BSIZE;
404         sbp->f_blocks = hpmp->hpm_su.su_btotal;
405         sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail;
406         sbp->f_ffree = 0;
407         sbp->f_files = 0;
408         sbp->f_flags = mp->mnt_flag;
409         
410         return (0);
411 }
412
413 /*ARGSUSED*/
414 static int
415 hpfs_fhtovp(
416         struct mount *mp,
417         struct fid *fhp,
418         struct vnode **vpp)
419 {
420         struct vnode *nvp;
421         struct hpfid *hpfhp = (struct hpfid *)fhp;
422         int error;
423
424         if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, LK_EXCLUSIVE, &nvp)) != 0) {
425                 *vpp = NULLVP;
426                 return (error);
427         }
428         /* XXX as unlink/rmdir/mkdir/creat are not currently possible
429          * with HPFS, we don't need to check anything else for now */
430         *vpp = nvp;
431
432         return (0);
433 }
434
435 static int
436 hpfs_vget(
437         struct mount *mp,
438         ino_t ino,
439         int flags,
440         struct vnode **vpp) 
441 {
442         struct hpfsmount *hpmp = VFSTOHPFS(mp);
443         struct vnode *vp;
444         struct hpfsnode *hp;
445         struct buf *bp;
446         int error;
447
448         dprintf(("hpfs_vget(0x%x): ",ino));
449
450         error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
451         if (error || *vpp != NULL)
452                 return (error);
453
454         *vpp = NULL;
455         hp = NULL;
456         vp = NULL;
457
458         /*
459          * We have to lock node creation for a while,
460          * but then we have to call getnewvnode(), 
461          * this may cause hpfs_reclaim() to be called,
462          * this may need to VOP_VGET() parent dir for
463          * update reasons, and if parent is not in
464          * hash, we have to lock node creation...
465          * To solve this, we MALLOC, getnewvnode and init while
466          * not locked (probability of node appearence
467          * at that time is little, and anyway - we'll
468          * check for it).
469          */
470         hp = malloc(sizeof(struct hpfsnode), 
471                 M_HPFSNO, M_WAITOK);
472
473         error = getnewvnode("hpfs", mp, &hpfs_vnodeops, &vp);
474         if (error) {
475                 printf("hpfs_vget: can't get new vnode\n");
476                 free(hp, M_HPFSNO);
477                 return (error);
478         }
479
480         dprintf(("prenew "));
481
482         vp->v_data = hp;
483
484         if (ino == (ino_t)hpmp->hpm_su.su_rootfno) 
485                 vp->v_vflag |= VV_ROOT;
486
487
488         mtx_init(&hp->h_interlock, "hpfsnode interlock", NULL, MTX_DEF);
489
490         hp->h_flag = H_INVAL;
491         hp->h_vp = vp;
492         hp->h_hpmp = hpmp;
493         hp->h_no = ino;
494         hp->h_dev = hpmp->hpm_dev;
495         hp->h_uid = hpmp->hpm_uid;
496         hp->h_gid = hpmp->hpm_uid;
497         hp->h_mode = hpmp->hpm_mode;
498         hp->h_devvp = hpmp->hpm_devvp;
499
500         lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
501         error = insmntque(vp, mp);
502         if (error != 0) {
503                 free(hp, M_HPFSNO);
504                 return (error);
505         }
506         error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL);
507         if (error || *vpp != NULL)
508                 return (error);
509
510         error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp);
511         if (error) {
512                 printf("hpfs_vget: can't read ino %d\n",ino);
513                 vput(vp);
514                 return (error);
515         }
516         bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode));
517         brelse(bp);
518
519         if (hp->h_fn.fn_magic != FN_MAGIC) {
520                 printf("hpfs_vget: MAGIC DOESN'T MATCH\n");
521                 vput(vp);
522                 return (EINVAL);
523         }
524
525         vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG;
526         hp->h_flag &= ~H_INVAL;
527
528         *vpp = vp;
529
530         return (0);
531 }
532
533 static struct vfsops hpfs_vfsops = {
534         .vfs_fhtovp =           hpfs_fhtovp,
535         .vfs_cmount =           hpfs_cmount,
536         .vfs_mount =            hpfs_mount,
537         .vfs_root =             hpfs_root,
538         .vfs_statfs =           hpfs_statfs,
539         .vfs_unmount =          hpfs_unmount,
540         .vfs_vget =             hpfs_vget,
541 };
542 VFS_SET(hpfs_vfsops, hpfs, 0);