]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/gnu/fs/xfs/FreeBSD/xfs_mountops.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / gnu / fs / xfs / FreeBSD / xfs_mountops.c
1 /*
2  * Copyright (c) 2001,2006 Alexander Kabaev, Russell Cattelan Digital Elves Inc.
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 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/proc.h>
33 #include <sys/malloc.h>
34 #include <sys/vnode.h>
35 #include <sys/mount.h>
36 #include <sys/namei.h>
37
38 #include <geom/geom.h>
39 #include <geom/geom_vfs.h>
40
41 #include "xfs.h"
42 #include "xfs_types.h"
43 #include "xfs_bit.h"
44 #include "xfs_inum.h"
45 #include "xfs_log.h"
46 #include "xfs_trans.h"
47 #include "xfs_sb.h"
48 #include "xfs_ag.h"
49 #include "xfs_dir.h"
50 #include "xfs_dir2.h"
51 #include "xfs_dmapi.h"
52 #include "xfs_mount.h"
53 #include "xfs_alloc_btree.h"
54 #include "xfs_bmap_btree.h"
55 #include "xfs_ialloc_btree.h"
56 #include "xfs_btree.h"
57 #include "xfs_attr_sf.h"
58 #include "xfs_dir_sf.h"
59 #include "xfs_dir2_sf.h"
60 #include "xfs_dinode.h"
61 #include "xfs_ialloc.h"
62 #include "xfs_inode.h"
63 #include "xfs_alloc.h"
64 #include "xfs_rtalloc.h"
65 #include "xfs_bmap.h"
66 #include "xfs_error.h"
67 #include "xfs_rw.h"
68 #include "xfs_quota.h"
69 #include "xfs_fsops.h"
70 #include "xfs_clnt.h"
71
72 #include <xfs_mountops.h>
73
74 static MALLOC_DEFINE(M_XFSNODE, "XFS node", "XFS vnode private part");
75
76 static vfs_mount_t      _xfs_mount;
77 static vfs_unmount_t    _xfs_unmount;
78 static vfs_root_t       _xfs_root;
79 static vfs_quotactl_t   _xfs_quotactl;
80 static vfs_statfs_t     _xfs_statfs;
81 static vfs_sync_t       _xfs_sync;
82 static vfs_vget_t       _xfs_vget;
83 static vfs_fhtovp_t     _xfs_fhtovp;
84 static vfs_init_t       _xfs_init;
85 static vfs_uninit_t     _xfs_uninit;
86 static vfs_extattrctl_t _xfs_extattrctl;
87
88 static b_strategy_t     xfs_geom_strategy;
89
90 static const char *xfs_opts[] =
91         { "from", "flags", "logbufs", "logbufsize",
92           "rtname", "logname", "iosizelog", "sunit",
93           "swidth", "export",
94           NULL };
95
96 static void
97 parse_int(struct mount *mp, const char *opt, int *val, int *error)
98 {
99         char *tmp, *ep;
100
101         tmp = vfs_getopts(mp->mnt_optnew, opt, error);
102         if (*error != 0) {
103                 return;
104         }
105         if (tmp != NULL) {
106                 *val = (int)strtol(tmp, &ep, 10);
107                 if (*ep) {
108                         *error = EINVAL;
109                         return;
110                 }
111         }
112 }
113
114 static int
115 _xfs_param_copyin(struct mount *mp, struct thread *td)
116 {
117         struct xfsmount *xmp = MNTTOXFS(mp);
118         struct xfs_mount_args *args = &xmp->m_args;
119         char *path;
120         char *fsname;
121         char *rtname;
122         char *logname;
123         int error;
124
125         path = vfs_getopts(mp->mnt_optnew, "fspath", &error);
126         if  (error)
127                 return (error);
128
129         bzero(args, sizeof(struct xfs_mount_args));
130         args->logbufs = -1;
131         args->logbufsize = -1;
132
133         parse_int(mp, "flags", &args->flags, &error);
134         if (error != 0 && error != ENOENT)
135                 return error;
136
137         args->flags |= XFSMNT_32BITINODES;
138
139         parse_int(mp, "sunit", &args->sunit, &error);
140         if (error != 0 && error != ENOENT)
141                 return error;
142
143         parse_int(mp, "swidth", &args->swidth, &error);
144         if (error != 0 && error != ENOENT)
145                 return error;
146
147         parse_int(mp, "logbufs", &args->logbufs, &error);
148         if (error != 0 && error != ENOENT)
149                 return error;
150
151         parse_int(mp, "logbufsize", &args->logbufsize, &error);
152         if (error != 0 && error != ENOENT)
153                 return error;
154
155         fsname = vfs_getopts(mp->mnt_optnew, "from", &error);
156         if (error == 0 && fsname != NULL) {
157                 strncpy(args->fsname, fsname, sizeof(args->fsname) - 1);
158         }
159
160         logname = vfs_getopts(mp->mnt_optnew, "logname", &error);
161         if (error == 0 && logname != NULL) {
162                 strncpy(args->logname, logname, sizeof(args->logname) - 1);
163         }
164
165         rtname = vfs_getopts(mp->mnt_optnew, "rtname", &error);
166         if (error == 0 && rtname != NULL) {
167                 strncpy(args->rtname, rtname, sizeof(args->rtname) - 1);
168         }
169
170         strncpy(args->mtpt, path, sizeof(args->mtpt));
171
172         printf("fsname '%s' logname '%s' rtname '%s'\n"
173                "flags 0x%x sunit %d swidth %d logbufs %d logbufsize %d\n",
174                args->fsname, args->logname, args->rtname, args->flags,
175                args->sunit, args->swidth, args->logbufs, args->logbufsize);
176
177         vfs_mountedfrom(mp, args->fsname);
178
179         return (0);
180 }
181
182 static int
183 _xfs_mount(struct mount         *mp)
184 {
185         struct xfsmount         *xmp;
186         struct xfs_vnode        *rootvp;
187         struct ucred            *curcred;
188         struct vnode            *rvp, *devvp;
189         struct cdev             *ddev;
190         struct g_consumer       *cp;
191         struct thread           *td;
192         int                     error;
193         
194         td = curthread;
195         ddev = NULL;
196         cp = NULL;
197
198         if (vfs_filteropt(mp->mnt_optnew, xfs_opts))
199                 return (EINVAL);
200
201         if (mp->mnt_flag & MNT_UPDATE)
202                 return (0);
203         if ((mp->mnt_flag & MNT_RDONLY) == 0)
204                 return (EPERM);
205
206         xmp = xfsmount_allocate(mp);
207         if (xmp == NULL)
208                 return (ENOMEM);
209
210         if((error = _xfs_param_copyin(mp, td)) != 0)
211                 goto fail;
212
213         curcred = td->td_ucred;
214         XVFS_MOUNT(XFSTOVFS(xmp), &xmp->m_args, curcred, error);
215         if (error)
216                 goto fail;
217
218         XVFS_ROOT(XFSTOVFS(xmp), &rootvp, error);
219         ddev = XFS_VFSTOM(XFSTOVFS(xmp))->m_ddev_targp->dev;
220         devvp = XFS_VFSTOM(XFSTOVFS(xmp))->m_ddev_targp->specvp;
221         if (error)
222                 goto fail_unmount;
223
224         if (ddev->si_iosize_max != 0)
225                 mp->mnt_iosize_max = ddev->si_iosize_max;
226         if (mp->mnt_iosize_max > MAXPHYS)
227                 mp->mnt_iosize_max = MAXPHYS;
228
229         mp->mnt_flag |= MNT_LOCAL;
230         mp->mnt_stat.f_fsid.val[0] = dev2udev(ddev);
231         mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
232
233         if ((error = VFS_STATFS(mp, &mp->mnt_stat)) != 0)
234                 goto fail_unmount;
235
236         rvp = rootvp->v_vnode;
237         rvp->v_vflag |= VV_ROOT;
238         VN_RELE(rootvp);
239
240         return (0);
241
242  fail_unmount:
243         XVFS_UNMOUNT(XFSTOVFS(xmp), 0, curcred, error);
244
245         if (devvp != NULL) {
246                 cp = devvp->v_bufobj.bo_private;
247                 if (cp != NULL) {
248                         DROP_GIANT();
249                         g_topology_lock();
250                         g_vfs_close(cp);
251                         g_topology_unlock();
252                         PICKUP_GIANT();
253                 }
254         }
255
256  fail:
257         if (xmp != NULL)
258                 xfsmount_deallocate(xmp);
259
260         return (error);
261 }
262
263 /*
264  * Free reference to null layer
265  */
266 static int
267 _xfs_unmount(mp, mntflags)
268         struct mount *mp;
269         int mntflags;
270 {
271         struct vnode *devvp;
272         struct g_consumer *cp;
273         int error;
274         cp = NULL;
275         devvp = NULL;
276
277         devvp = XFS_VFSTOM((MNTTOVFS(mp)))->m_ddev_targp->specvp;
278         if (devvp != NULL)
279                 cp = devvp->v_bufobj.bo_private;
280
281         XVFS_UNMOUNT(MNTTOVFS(mp), 0, curthread->td_ucred, error);
282         if (error == 0) {
283                 if (cp != NULL) {
284                         DROP_GIANT();
285                         g_topology_lock();
286                         g_vfs_close(cp);
287                         g_topology_unlock();
288                         PICKUP_GIANT();
289                 }
290         }
291         return (error);
292 }
293
294 static int
295 _xfs_root(mp, flags, vpp)
296         struct mount *mp;
297         int flags;
298         struct vnode **vpp;
299 {
300         xfs_vnode_t *vp;
301         int error;
302
303         XVFS_ROOT(MNTTOVFS(mp), &vp, error);
304         if (error == 0) {
305                 *vpp = vp->v_vnode;
306                 VOP_LOCK(*vpp, flags);
307         }
308         return (error);
309 }
310
311 static int
312 _xfs_quotactl(mp, cmd, uid, arg)
313         struct mount *mp;
314         int cmd;
315         uid_t uid;
316         void *arg;
317 {
318         printf("xfs_quotactl\n");
319         return EOPNOTSUPP;
320 }
321
322 static int
323 _xfs_statfs(mp, sbp)
324         struct mount *mp;
325         struct statfs *sbp;
326 {
327         int error;
328
329         XVFS_STATVFS(MNTTOVFS(mp), sbp, NULL, error);
330         if (error)
331                 return error;
332
333         /* Fix up the values XFS statvfs calls does not know about. */
334         sbp->f_iosize = sbp->f_bsize;
335
336         return (error);
337 }
338
339 static int
340 _xfs_sync(mp, waitfor)
341         struct mount *mp;
342         int waitfor;
343 {
344         int error;
345         int flags = SYNC_FSDATA|SYNC_ATTR|SYNC_REFCACHE;
346
347         if (waitfor == MNT_WAIT)
348                 flags |= SYNC_WAIT;
349         else if (waitfor == MNT_LAZY)
350                 flags |= SYNC_BDFLUSH;
351         XVFS_SYNC(MNTTOVFS(mp), flags, curthread->td_ucred, error);
352         return (error);
353 }
354
355 static int
356 _xfs_vget(mp, ino, flags, vpp)
357         struct mount *mp;
358         ino_t ino;
359         int flags;
360         struct vnode **vpp;
361 {
362         xfs_vnode_t *vp = NULL;
363         int error;
364
365         printf("XVFS_GET_VNODE(MNTTOVFS(mp), &vp, ino, error);\n");
366         error = ENOSYS;
367         if (error == 0)
368                 *vpp = vp->v_vnode;
369         return (error);
370 }
371
372 static int
373 _xfs_fhtovp(mp, fidp, flags, vpp)
374         struct mount *mp;
375         struct fid *fidp;
376         int flags;
377         struct vnode **vpp;
378 {
379         printf("xfs_fhtovp\n");
380         return ENOSYS;
381 }
382
383 static int
384 _xfs_extattrctl(struct mount *mp, int cm,
385                 struct vnode *filename_v,
386                 int attrnamespace, const char *attrname)
387 {
388         printf("xfs_extattrctl\n");
389         return ENOSYS;
390 }
391
392 int
393 _xfs_init(vfsp)
394         struct vfsconf *vfsp;
395 {
396         int error;
397
398         error = init_xfs_fs();
399
400         return (error);
401 }
402
403 int
404 _xfs_uninit(vfsp)
405         struct vfsconf *vfsp;
406 {
407         exit_xfs_fs();
408         return 0;
409 }
410
411 static struct vfsops xfs_fsops = {
412         .vfs_mount =    _xfs_mount,
413         .vfs_unmount =  _xfs_unmount,
414         .vfs_root =     _xfs_root,
415         .vfs_quotactl = _xfs_quotactl,
416         .vfs_statfs =   _xfs_statfs,
417         .vfs_sync =     _xfs_sync,
418         .vfs_vget =     _xfs_vget,
419         .vfs_fhtovp =   _xfs_fhtovp,
420         .vfs_init =     _xfs_init,
421         .vfs_uninit =   _xfs_uninit,
422         .vfs_extattrctl = _xfs_extattrctl,
423 };
424
425 VFS_SET(xfs_fsops, xfs, 0);
426
427 /*
428  *  Copy GEOM VFS functions here to provide a conveniet place to
429  *  track all XFS-related IO without being distracted by other
430  *  filesystems which happen to be mounted on the machine at the
431  *  same time.
432  */
433
434 static void
435 xfs_geom_biodone(struct bio *bip)
436 {
437         struct buf *bp;
438
439         if (bip->bio_error) {
440                 printf("g_vfs_done():");
441                 g_print_bio(bip);
442                 printf("error = %d\n", bip->bio_error);
443         }
444         bp = bip->bio_caller2;
445         bp->b_error = bip->bio_error;
446         bp->b_ioflags = bip->bio_flags;
447         if (bip->bio_error)
448                 bp->b_ioflags |= BIO_ERROR;
449         bp->b_resid = bp->b_bcount - bip->bio_completed;
450         g_destroy_bio(bip);
451         mtx_lock(&Giant);
452         bufdone(bp);
453         mtx_unlock(&Giant);
454 }
455
456 static void
457 xfs_geom_strategy(struct bufobj *bo, struct buf *bp)
458 {
459         struct g_consumer *cp;
460         struct bio *bip;
461
462         cp = bo->bo_private;
463         G_VALID_CONSUMER(cp);
464
465         bip = g_alloc_bio();
466         bip->bio_cmd = bp->b_iocmd;
467         bip->bio_offset = bp->b_iooffset;
468         bip->bio_data = bp->b_data;
469         bip->bio_done = xfs_geom_biodone;
470         bip->bio_caller2 = bp;
471         bip->bio_length = bp->b_bcount;
472         g_io_request(bip, cp);
473 }
474
475 static int
476 xfs_geom_bufwrite(struct buf *bp)
477 {
478         return bufwrite(bp);
479 }
480
481 static int
482 xfs_geom_bufsync(struct bufobj *bo, int waitfor)
483 {
484
485         return (bufsync(bo, waitfor));
486 }
487
488 static void
489 xfs_geom_bufbdflush(struct bufobj *bo, struct buf *bp)
490 {
491         bufbdflush(bo, bp);
492 }
493
494 struct buf_ops xfs_bo_ops = {
495         .bop_name =     "XFS",
496         .bop_write =    xfs_geom_bufwrite,
497         .bop_strategy = xfs_geom_strategy,
498         .bop_sync =     xfs_geom_bufsync,
499         .bop_bdflush =  xfs_geom_bufbdflush,
500 };