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