1*b5860281Sandvar /* $NetBSD: nilfs_vfsops.c,v 1.27 2021/09/16 22:19:11 andvar Exp $ */
269a586f2Sreinoud
369a586f2Sreinoud /*
469a586f2Sreinoud * Copyright (c) 2008, 2009 Reinoud Zandijk
569a586f2Sreinoud * All rights reserved.
669a586f2Sreinoud *
769a586f2Sreinoud * Redistribution and use in source and binary forms, with or without
869a586f2Sreinoud * modification, are permitted provided that the following conditions
969a586f2Sreinoud * are met:
1069a586f2Sreinoud * 1. Redistributions of source code must retain the above copyright
1169a586f2Sreinoud * notice, this list of conditions and the following disclaimer.
1269a586f2Sreinoud * 2. Redistributions in binary form must reproduce the above copyright
1369a586f2Sreinoud * notice, this list of conditions and the following disclaimer in the
1469a586f2Sreinoud * documentation and/or other materials provided with the distribution.
1569a586f2Sreinoud *
1669a586f2Sreinoud * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1769a586f2Sreinoud * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1869a586f2Sreinoud * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1969a586f2Sreinoud * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2069a586f2Sreinoud * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2169a586f2Sreinoud * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2269a586f2Sreinoud * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2369a586f2Sreinoud * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2469a586f2Sreinoud * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2569a586f2Sreinoud * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2669a586f2Sreinoud *
2769a586f2Sreinoud */
2869a586f2Sreinoud
2969a586f2Sreinoud #include <sys/cdefs.h>
3069a586f2Sreinoud #ifndef lint
31*b5860281Sandvar __KERNEL_RCSID(0, "$NetBSD: nilfs_vfsops.c,v 1.27 2021/09/16 22:19:11 andvar Exp $");
3269a586f2Sreinoud #endif /* not lint */
3369a586f2Sreinoud
3469a586f2Sreinoud
3569a586f2Sreinoud #if defined(_KERNEL_OPT)
3669a586f2Sreinoud #include "opt_compat_netbsd.h"
3769a586f2Sreinoud #endif
3869a586f2Sreinoud
3969a586f2Sreinoud #include <sys/param.h>
4069a586f2Sreinoud #include <sys/systm.h>
4169a586f2Sreinoud #include <sys/sysctl.h>
4269a586f2Sreinoud #include <sys/namei.h>
4369a586f2Sreinoud #include <sys/proc.h>
4469a586f2Sreinoud #include <sys/kernel.h>
4569a586f2Sreinoud #include <sys/vnode.h>
4669a586f2Sreinoud #include <miscfs/genfs/genfs.h>
4769a586f2Sreinoud #include <miscfs/specfs/specdev.h>
4869a586f2Sreinoud #include <sys/mount.h>
4969a586f2Sreinoud #include <sys/buf.h>
5069a586f2Sreinoud #include <sys/file.h>
5169a586f2Sreinoud #include <sys/device.h>
5269a586f2Sreinoud #include <sys/disklabel.h>
5369a586f2Sreinoud #include <sys/ioctl.h>
5469a586f2Sreinoud #include <sys/malloc.h>
5569a586f2Sreinoud #include <sys/dirent.h>
5669a586f2Sreinoud #include <sys/stat.h>
5769a586f2Sreinoud #include <sys/conf.h>
5869a586f2Sreinoud #include <sys/kauth.h>
5969a586f2Sreinoud #include <sys/module.h>
6069a586f2Sreinoud
6169a586f2Sreinoud #include <fs/nilfs/nilfs_mount.h>
6269a586f2Sreinoud #include <sys/dirhash.h>
6369a586f2Sreinoud
6469a586f2Sreinoud
6569a586f2Sreinoud #include "nilfs.h"
6669a586f2Sreinoud #include "nilfs_subr.h"
6769a586f2Sreinoud #include "nilfs_bswap.h"
6869a586f2Sreinoud
6969a586f2Sreinoud MODULE(MODULE_CLASS_VFS, nilfs, NULL);
7069a586f2Sreinoud
7169a586f2Sreinoud #define VTOI(vnode) ((struct nilfs_node *) vnode->v_data)
7269a586f2Sreinoud
7369a586f2Sreinoud /* verbose levels of the nilfs filingsystem */
7469a586f2Sreinoud int nilfs_verbose = NILFS_DEBUGGING;
7569a586f2Sreinoud
7669a586f2Sreinoud /* malloc regions */
7769a586f2Sreinoud MALLOC_JUSTDEFINE(M_NILFSMNT, "NILFS mount", "NILFS mount structures");
7869a586f2Sreinoud MALLOC_JUSTDEFINE(M_NILFSTEMP, "NILFS temp", "NILFS scrap space");
7969a586f2Sreinoud struct pool nilfs_node_pool;
8069a586f2Sreinoud
8169a586f2Sreinoud /* globals */
8269a586f2Sreinoud struct _nilfs_devices nilfs_devices;
8369a586f2Sreinoud
8469a586f2Sreinoud /* supported functions predefined */
8569a586f2Sreinoud VFS_PROTOS(nilfs);
8669a586f2Sreinoud
8769a586f2Sreinoud
8869a586f2Sreinoud /* --------------------------------------------------------------------- */
8969a586f2Sreinoud
90668c7daaShannken /*
91668c7daaShannken * Genfs interfacing
92668c7daaShannken *
93668c7daaShannken * static const struct genfs_ops nilfs_genfsops = {
94668c7daaShannken * .gop_size = genfs_size,
95668c7daaShannken * size of transfers
96668c7daaShannken * .gop_alloc = nilfs_gop_alloc,
97668c7daaShannken * allocate len bytes at offset
98668c7daaShannken * .gop_write = genfs_gop_write,
99668c7daaShannken * putpages interface code
100668c7daaShannken * .gop_markupdate = nilfs_gop_markupdate,
101668c7daaShannken * set update/modify flags etc.
102668c7daaShannken * }
103668c7daaShannken */
104668c7daaShannken
105668c7daaShannken /*
106668c7daaShannken * Callback from genfs to allocate len bytes at offset off; only called when
107668c7daaShannken * filling up gaps in the allocation.
108668c7daaShannken */
109668c7daaShannken static int
nilfs_gop_alloc(struct vnode * vp,off_t off,off_t len,int flags,kauth_cred_t cred)110668c7daaShannken nilfs_gop_alloc(struct vnode *vp, off_t off,
111668c7daaShannken off_t len, int flags, kauth_cred_t cred)
112668c7daaShannken {
113668c7daaShannken DPRINTF(NOTIMPL, ("nilfs_gop_alloc not implemented\n"));
114668c7daaShannken DPRINTF(ALLOC, ("nilfs_gop_alloc called for %"PRIu64" bytes\n", len));
115668c7daaShannken
116668c7daaShannken return 0;
117668c7daaShannken }
118668c7daaShannken
119668c7daaShannken
120668c7daaShannken /*
121668c7daaShannken * callback from genfs to update our flags
122668c7daaShannken */
123668c7daaShannken static void
nilfs_gop_markupdate(struct vnode * vp,int flags)124668c7daaShannken nilfs_gop_markupdate(struct vnode *vp, int flags)
125668c7daaShannken {
126668c7daaShannken struct nilfs_node *nilfs_node = VTOI(vp);
127668c7daaShannken u_long mask = 0;
128668c7daaShannken
129668c7daaShannken if ((flags & GOP_UPDATE_ACCESSED) != 0) {
130668c7daaShannken mask = IN_ACCESS;
131668c7daaShannken }
132668c7daaShannken if ((flags & GOP_UPDATE_MODIFIED) != 0) {
133668c7daaShannken if (vp->v_type == VREG) {
134668c7daaShannken mask |= IN_CHANGE | IN_UPDATE;
135668c7daaShannken } else {
136668c7daaShannken mask |= IN_MODIFY;
137668c7daaShannken }
138668c7daaShannken }
139668c7daaShannken if (mask) {
140668c7daaShannken nilfs_node->i_flags |= mask;
141668c7daaShannken }
142668c7daaShannken }
143668c7daaShannken
144668c7daaShannken
145668c7daaShannken static const struct genfs_ops nilfs_genfsops = {
146668c7daaShannken .gop_size = genfs_size,
147668c7daaShannken .gop_alloc = nilfs_gop_alloc,
148668c7daaShannken .gop_write = genfs_gop_write_rwmap,
149668c7daaShannken .gop_markupdate = nilfs_gop_markupdate,
150e406c140Schs .gop_putrange = genfs_gop_putrange,
151668c7daaShannken };
152668c7daaShannken
153668c7daaShannken /* --------------------------------------------------------------------- */
154668c7daaShannken
15569a586f2Sreinoud /* predefine vnode-op list descriptor */
15669a586f2Sreinoud extern const struct vnodeopv_desc nilfs_vnodeop_opv_desc;
15769a586f2Sreinoud
15869a586f2Sreinoud const struct vnodeopv_desc * const nilfs_vnodeopv_descs[] = {
15969a586f2Sreinoud &nilfs_vnodeop_opv_desc,
16069a586f2Sreinoud NULL,
16169a586f2Sreinoud };
16269a586f2Sreinoud
16369a586f2Sreinoud
16469a586f2Sreinoud /* vfsops descriptor linked in as anchor point for the filingsystem */
16569a586f2Sreinoud struct vfsops nilfs_vfsops = {
1666d285189Shannken .vfs_name = MOUNT_NILFS,
1676d285189Shannken .vfs_min_mount_data = sizeof (struct nilfs_args),
1686d285189Shannken .vfs_mount = nilfs_mount,
1696d285189Shannken .vfs_start = nilfs_start,
1706d285189Shannken .vfs_unmount = nilfs_unmount,
1716d285189Shannken .vfs_root = nilfs_root,
1726d285189Shannken .vfs_quotactl = (void *)eopnotsupp,
1736d285189Shannken .vfs_statvfs = nilfs_statvfs,
1746d285189Shannken .vfs_sync = nilfs_sync,
1756d285189Shannken .vfs_vget = nilfs_vget,
176668c7daaShannken .vfs_loadvnode = nilfs_loadvnode,
1776d285189Shannken .vfs_fhtovp = nilfs_fhtovp,
1786d285189Shannken .vfs_vptofh = nilfs_vptofh,
1796d285189Shannken .vfs_init = nilfs_init,
1806d285189Shannken .vfs_reinit = nilfs_reinit,
1816d285189Shannken .vfs_done = nilfs_done,
1826d285189Shannken .vfs_mountroot = nilfs_mountroot,
1836d285189Shannken .vfs_snapshot = nilfs_snapshot,
1846d285189Shannken .vfs_extattrctl = vfs_stdextattrctl,
185326db3aaShannken .vfs_suspendctl = genfs_suspendctl,
1866d285189Shannken .vfs_renamelock_enter = genfs_renamelock_enter,
1876d285189Shannken .vfs_renamelock_exit = genfs_renamelock_exit,
1886d285189Shannken .vfs_fsync = (void *)eopnotsupp,
1896d285189Shannken .vfs_opv_descs = nilfs_vnodeopv_descs
19069a586f2Sreinoud };
19169a586f2Sreinoud
19269a586f2Sreinoud /* --------------------------------------------------------------------- */
19369a586f2Sreinoud
19469a586f2Sreinoud /* file system starts here */
19569a586f2Sreinoud void
nilfs_init(void)19669a586f2Sreinoud nilfs_init(void)
19769a586f2Sreinoud {
19869a586f2Sreinoud size_t size;
19969a586f2Sreinoud
20069a586f2Sreinoud /* setup memory types */
20169a586f2Sreinoud malloc_type_attach(M_NILFSMNT);
20269a586f2Sreinoud malloc_type_attach(M_NILFSTEMP);
20369a586f2Sreinoud
20469a586f2Sreinoud /* init device lists */
20569a586f2Sreinoud SLIST_INIT(&nilfs_devices);
20669a586f2Sreinoud
20769a586f2Sreinoud /* init node pools */
20869a586f2Sreinoud size = sizeof(struct nilfs_node);
20969a586f2Sreinoud pool_init(&nilfs_node_pool, size, 0, 0, 0,
21069a586f2Sreinoud "nilfs_node_pool", NULL, IPL_NONE);
21169a586f2Sreinoud }
21269a586f2Sreinoud
21369a586f2Sreinoud
21469a586f2Sreinoud void
nilfs_reinit(void)21569a586f2Sreinoud nilfs_reinit(void)
21669a586f2Sreinoud {
21769a586f2Sreinoud /* nothing to do */
21869a586f2Sreinoud }
21969a586f2Sreinoud
22069a586f2Sreinoud
22169a586f2Sreinoud void
nilfs_done(void)22269a586f2Sreinoud nilfs_done(void)
22369a586f2Sreinoud {
22469a586f2Sreinoud /* remove pools */
22569a586f2Sreinoud pool_destroy(&nilfs_node_pool);
22669a586f2Sreinoud
22769a586f2Sreinoud malloc_type_detach(M_NILFSMNT);
22869a586f2Sreinoud malloc_type_detach(M_NILFSTEMP);
22969a586f2Sreinoud }
23069a586f2Sreinoud
23169a586f2Sreinoud /*
23269a586f2Sreinoud * If running a DEBUG kernel, provide an easy way to set the debug flags when
23369a586f2Sreinoud * running into a problem.
23469a586f2Sreinoud */
23569a586f2Sreinoud #define NILFS_VERBOSE_SYSCTLOPT 1
23669a586f2Sreinoud
2379120d451Spgoyette SYSCTL_SETUP(nilfs_sysctl_setup, "nilfs sysctl")
2389120d451Spgoyette {
2399120d451Spgoyette const struct sysctlnode *node;
2409120d451Spgoyette
2419120d451Spgoyette /*
2429120d451Spgoyette * XXX the "30" below could be dynamic, thereby eliminating one
2439120d451Spgoyette * more instance of the "number to vfs" mapping problem, but
2449120d451Spgoyette * "30" is the order as taken from sys/mount.h
2459120d451Spgoyette */
2469120d451Spgoyette sysctl_createv(clog, 0, NULL, &node,
2479120d451Spgoyette CTLFLAG_PERMANENT,
2489120d451Spgoyette CTLTYPE_NODE, "nilfs",
2499120d451Spgoyette SYSCTL_DESCR("NTT's NILFSv2"),
2509120d451Spgoyette NULL, 0, NULL, 0,
2519120d451Spgoyette CTL_VFS, 30, CTL_EOL);
2529120d451Spgoyette #ifdef DEBUG
2539120d451Spgoyette sysctl_createv(clog, 0, NULL, &node,
2549120d451Spgoyette CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
2559120d451Spgoyette CTLTYPE_INT, "verbose",
2569120d451Spgoyette SYSCTL_DESCR("Bitmask for filesystem debugging"),
2579120d451Spgoyette NULL, 0, &nilfs_verbose, 0,
2589120d451Spgoyette CTL_VFS, 30, NILFS_VERBOSE_SYSCTLOPT, CTL_EOL);
2599120d451Spgoyette #endif
2609120d451Spgoyette }
2619120d451Spgoyette
26269a586f2Sreinoud static int
nilfs_modcmd(modcmd_t cmd,void * arg)26369a586f2Sreinoud nilfs_modcmd(modcmd_t cmd, void *arg)
26469a586f2Sreinoud {
26569a586f2Sreinoud int error;
26669a586f2Sreinoud
26769a586f2Sreinoud switch (cmd) {
26869a586f2Sreinoud case MODULE_CMD_INIT:
26969a586f2Sreinoud error = vfs_attach(&nilfs_vfsops);
27069a586f2Sreinoud if (error != 0)
27169a586f2Sreinoud break;
27269a586f2Sreinoud break;
27369a586f2Sreinoud case MODULE_CMD_FINI:
27469a586f2Sreinoud error = vfs_detach(&nilfs_vfsops);
27569a586f2Sreinoud if (error != 0)
27669a586f2Sreinoud break;
27769a586f2Sreinoud break;
27869a586f2Sreinoud default:
27969a586f2Sreinoud error = ENOTTY;
28069a586f2Sreinoud break;
28169a586f2Sreinoud }
28269a586f2Sreinoud
28369a586f2Sreinoud return (error);
28469a586f2Sreinoud }
28569a586f2Sreinoud
28669a586f2Sreinoud /* --------------------------------------------------------------------- */
28769a586f2Sreinoud
28869a586f2Sreinoud int
nilfs_mountroot(void)28969a586f2Sreinoud nilfs_mountroot(void)
29069a586f2Sreinoud {
29169a586f2Sreinoud return EOPNOTSUPP;
29269a586f2Sreinoud }
29369a586f2Sreinoud
29469a586f2Sreinoud /* --------------------------------------------------------------------- */
29569a586f2Sreinoud
29669a586f2Sreinoud /* system nodes */
29769a586f2Sreinoud static int
nilfs_create_system_nodes(struct nilfs_device * nilfsdev)29869a586f2Sreinoud nilfs_create_system_nodes(struct nilfs_device *nilfsdev)
29969a586f2Sreinoud {
30069a586f2Sreinoud int error;
30169a586f2Sreinoud
30269a586f2Sreinoud error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_DAT_INO,
30369a586f2Sreinoud &nilfsdev->super_root.sr_dat, &nilfsdev->dat_node);
30469a586f2Sreinoud if (error)
30569a586f2Sreinoud goto errorout;
30669a586f2Sreinoud
30769a586f2Sreinoud error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_CPFILE_INO,
30869a586f2Sreinoud &nilfsdev->super_root.sr_cpfile, &nilfsdev->cp_node);
30969a586f2Sreinoud if (error)
31069a586f2Sreinoud goto errorout;
31169a586f2Sreinoud
31269a586f2Sreinoud error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_SUFILE_INO,
31369a586f2Sreinoud &nilfsdev->super_root.sr_sufile, &nilfsdev->su_node);
31469a586f2Sreinoud if (error)
31569a586f2Sreinoud goto errorout;
31669a586f2Sreinoud
31769a586f2Sreinoud return 0;
31869a586f2Sreinoud errorout:
31969a586f2Sreinoud nilfs_dispose_node(&nilfsdev->dat_node);
32069a586f2Sreinoud nilfs_dispose_node(&nilfsdev->cp_node);
32169a586f2Sreinoud nilfs_dispose_node(&nilfsdev->su_node);
32269a586f2Sreinoud
32369a586f2Sreinoud return error;
32469a586f2Sreinoud }
32569a586f2Sreinoud
32669a586f2Sreinoud
32769a586f2Sreinoud static void
nilfs_release_system_nodes(struct nilfs_device * nilfsdev)32869a586f2Sreinoud nilfs_release_system_nodes(struct nilfs_device *nilfsdev)
32969a586f2Sreinoud {
33069a586f2Sreinoud if (!nilfsdev)
33169a586f2Sreinoud return;
33269a586f2Sreinoud if (nilfsdev->refcnt > 0)
33369a586f2Sreinoud return;
33469a586f2Sreinoud
33569a586f2Sreinoud nilfs_dispose_node(&nilfsdev->dat_node);
33669a586f2Sreinoud nilfs_dispose_node(&nilfsdev->cp_node);
33769a586f2Sreinoud nilfs_dispose_node(&nilfsdev->su_node);
33869a586f2Sreinoud }
33969a586f2Sreinoud
34069a586f2Sreinoud
34169a586f2Sreinoud /* --------------------------------------------------------------------- */
34269a586f2Sreinoud
34369a586f2Sreinoud static int
nilfs_check_superblock_crc(struct nilfs_super_block * super)34469a586f2Sreinoud nilfs_check_superblock_crc(struct nilfs_super_block *super)
34569a586f2Sreinoud {
34669a586f2Sreinoud uint32_t super_crc, comp_crc;
34769a586f2Sreinoud
34869a586f2Sreinoud /* check super block magic */
34969a586f2Sreinoud if (nilfs_rw16(super->s_magic) != NILFS_SUPER_MAGIC)
35069a586f2Sreinoud return 0;
35169a586f2Sreinoud
35269a586f2Sreinoud /* preserve crc */
35369a586f2Sreinoud super_crc = nilfs_rw32(super->s_sum);
35469a586f2Sreinoud
35569a586f2Sreinoud /* calculate */
35669a586f2Sreinoud super->s_sum = 0;
35769a586f2Sreinoud comp_crc = crc32_le(nilfs_rw32(super->s_crc_seed),
35869a586f2Sreinoud (uint8_t *) super, nilfs_rw16(super->s_bytes));
35969a586f2Sreinoud
36069a586f2Sreinoud /* restore */
36169a586f2Sreinoud super->s_sum = nilfs_rw32(super_crc);
36269a586f2Sreinoud
36369a586f2Sreinoud /* check CRC */
36469a586f2Sreinoud return (super_crc == comp_crc);
36569a586f2Sreinoud }
36669a586f2Sreinoud
36769a586f2Sreinoud
36869a586f2Sreinoud
36969a586f2Sreinoud static int
nilfs_read_superblock(struct nilfs_device * nilfsdev)37069a586f2Sreinoud nilfs_read_superblock(struct nilfs_device *nilfsdev)
37169a586f2Sreinoud {
37269a586f2Sreinoud struct nilfs_super_block *super, tmp_super;
37369a586f2Sreinoud struct buf *bp;
37469a586f2Sreinoud uint64_t sb1off, sb2off;
375bb702d32Sreinoud uint64_t last_cno1, last_cno2;
37669a586f2Sreinoud uint64_t dev_blk;
37769a586f2Sreinoud int dev_bsize, dev_blks;
37869a586f2Sreinoud int sb1ok, sb2ok, swp;
37969a586f2Sreinoud int error;
38069a586f2Sreinoud
38169a586f2Sreinoud sb1off = NILFS_SB_OFFSET_BYTES;
38269a586f2Sreinoud sb2off = NILFS_SB2_OFFSET_BYTES(nilfsdev->devsize);
38369a586f2Sreinoud
38469a586f2Sreinoud dev_bsize = 1 << nilfsdev->devvp->v_mount->mnt_fs_bshift;
38569a586f2Sreinoud
38669a586f2Sreinoud /* read our superblock regardless of backing device blocksize */
38769a586f2Sreinoud dev_blk = 0;
38869a586f2Sreinoud dev_blks = (sb1off + dev_bsize -1)/dev_bsize;
3896e392401Smaxv error = bread(nilfsdev->devvp, dev_blk, dev_blks * dev_bsize, 0, &bp);
39069a586f2Sreinoud if (error) {
39169a586f2Sreinoud return error;
39269a586f2Sreinoud }
39369a586f2Sreinoud
39469a586f2Sreinoud /* copy read-in super block at the offset */
39569a586f2Sreinoud super = &nilfsdev->super;
39669a586f2Sreinoud memcpy(super, (uint8_t *) bp->b_data + NILFS_SB_OFFSET_BYTES,
39769a586f2Sreinoud sizeof(struct nilfs_super_block));
39869a586f2Sreinoud brelse(bp, BC_AGE);
39969a586f2Sreinoud
40069a586f2Sreinoud /* read our 2nd superblock regardless of backing device blocksize */
40169a586f2Sreinoud dev_blk = sb2off / dev_bsize;
40269a586f2Sreinoud dev_blks = 2; /* assumption max one dev_bsize */
4036e392401Smaxv error = bread(nilfsdev->devvp, dev_blk, dev_blks * dev_bsize, 0, &bp);
40469a586f2Sreinoud if (error) {
40569a586f2Sreinoud return error;
40669a586f2Sreinoud }
40769a586f2Sreinoud
40869a586f2Sreinoud /* copy read-in superblock2 at the offset */
40969a586f2Sreinoud super = &nilfsdev->super2;
41069a586f2Sreinoud memcpy(super, (uint8_t *) bp->b_data + NILFS_SB_OFFSET_BYTES,
41169a586f2Sreinoud sizeof(struct nilfs_super_block));
41269a586f2Sreinoud brelse(bp, BC_AGE);
41369a586f2Sreinoud
41469a586f2Sreinoud sb1ok = nilfs_check_superblock_crc(&nilfsdev->super);
41569a586f2Sreinoud sb2ok = nilfs_check_superblock_crc(&nilfsdev->super2);
41669a586f2Sreinoud
417bb702d32Sreinoud last_cno1 = nilfs_rw64(nilfsdev->super.s_last_cno);
418bb702d32Sreinoud last_cno2 = nilfs_rw64(nilfsdev->super2.s_last_cno);
419bb702d32Sreinoud swp = sb2ok && (last_cno2 > last_cno1);
42069a586f2Sreinoud
42169a586f2Sreinoud if (swp) {
42269a586f2Sreinoud printf("nilfs warning: broken superblock, using spare\n");
42369a586f2Sreinoud tmp_super = nilfsdev->super2;
42469a586f2Sreinoud nilfsdev->super2 = nilfsdev->super; /* why preserve? */
42569a586f2Sreinoud nilfsdev->super = tmp_super;
42669a586f2Sreinoud }
42769a586f2Sreinoud
42869a586f2Sreinoud if (!sb1ok && !sb2ok) {
42969a586f2Sreinoud printf("nilfs: no valid superblocks found\n");
43069a586f2Sreinoud return EINVAL;
43169a586f2Sreinoud }
43269a586f2Sreinoud
43369a586f2Sreinoud return 0;
43469a586f2Sreinoud }
43569a586f2Sreinoud
43669a586f2Sreinoud
43769a586f2Sreinoud /* XXX NOTHING from the system nodes should need to be written here */
43869a586f2Sreinoud static void
nilfs_unmount_base(struct nilfs_device * nilfsdev)43969a586f2Sreinoud nilfs_unmount_base(struct nilfs_device *nilfsdev)
44069a586f2Sreinoud {
441c77065c1Smrg int error __diagused;
44269a586f2Sreinoud
44369a586f2Sreinoud if (!nilfsdev)
44469a586f2Sreinoud return;
44569a586f2Sreinoud
44669a586f2Sreinoud /* remove all our information */
44769a586f2Sreinoud error = vinvalbuf(nilfsdev->devvp, 0, FSCRED, curlwp, 0, 0);
44869a586f2Sreinoud KASSERT(error == 0);
44969a586f2Sreinoud
45069a586f2Sreinoud /* release the device's system nodes */
45169a586f2Sreinoud nilfs_release_system_nodes(nilfsdev);
45269a586f2Sreinoud
45369a586f2Sreinoud /* TODO writeout super_block? */
45469a586f2Sreinoud }
45569a586f2Sreinoud
45669a586f2Sreinoud
45769a586f2Sreinoud static int
nilfs_mount_base(struct nilfs_device * nilfsdev,struct mount * mp,struct nilfs_args * args)45869a586f2Sreinoud nilfs_mount_base(struct nilfs_device *nilfsdev,
45969a586f2Sreinoud struct mount *mp, struct nilfs_args *args)
46069a586f2Sreinoud {
46169a586f2Sreinoud struct lwp *l = curlwp;
46269a586f2Sreinoud uint64_t last_pseg, last_cno, last_seq;
46369a586f2Sreinoud uint32_t log_blocksize;
46469a586f2Sreinoud int error;
46569a586f2Sreinoud
46669a586f2Sreinoud /* flush out any old buffers remaining from a previous use. */
46769a586f2Sreinoud if ((error = vinvalbuf(nilfsdev->devvp, V_SAVE, l->l_cred, l, 0, 0)))
46869a586f2Sreinoud return error;
46969a586f2Sreinoud
47069a586f2Sreinoud /* read in our superblock */
47169a586f2Sreinoud error = nilfs_read_superblock(nilfsdev);
47269a586f2Sreinoud if (error) {
47369a586f2Sreinoud printf("nilfs_mount: can't read in super block : %d\n", error);
47469a586f2Sreinoud return error;
47569a586f2Sreinoud }
47669a586f2Sreinoud
47769a586f2Sreinoud /* get our blocksize */
47869a586f2Sreinoud log_blocksize = nilfs_rw32(nilfsdev->super.s_log_block_size);
47969a586f2Sreinoud nilfsdev->blocksize = (uint64_t) 1 << (log_blocksize + 10);
48069a586f2Sreinoud /* TODO check superblock's blocksize limits */
48169a586f2Sreinoud
48269a586f2Sreinoud /* calculate dat structure parameters */
48369a586f2Sreinoud nilfs_calc_mdt_consts(nilfsdev, &nilfsdev->dat_mdt,
48469a586f2Sreinoud nilfs_rw16(nilfsdev->super.s_dat_entry_size));
48569a586f2Sreinoud nilfs_calc_mdt_consts(nilfsdev, &nilfsdev->ifile_mdt,
48669a586f2Sreinoud nilfs_rw16(nilfsdev->super.s_inode_size));
48769a586f2Sreinoud
48869a586f2Sreinoud DPRINTF(VOLUMES, ("nilfs_mount: accepted super block\n"));
48969a586f2Sreinoud
49069a586f2Sreinoud /* search for the super root and roll forward when needed */
49169a586f2Sreinoud nilfs_search_super_root(nilfsdev);
49269a586f2Sreinoud
49369a586f2Sreinoud nilfsdev->mount_state = nilfs_rw16(nilfsdev->super.s_state);
49469a586f2Sreinoud if (nilfsdev->mount_state != NILFS_VALID_FS) {
49569a586f2Sreinoud printf("FS is seriously damaged, needs repairing\n");
49669a586f2Sreinoud printf("aborting mount\n");
49769a586f2Sreinoud return EINVAL;
49869a586f2Sreinoud }
49969a586f2Sreinoud
50069a586f2Sreinoud /*
50169a586f2Sreinoud * FS should be ok now. The superblock and the last segsum could be
50269a586f2Sreinoud * updated from the repair so extract running values again.
50369a586f2Sreinoud */
50469a586f2Sreinoud last_pseg = nilfs_rw64(nilfsdev->super.s_last_pseg); /*blknr */
50569a586f2Sreinoud last_cno = nilfs_rw64(nilfsdev->super.s_last_cno);
50669a586f2Sreinoud last_seq = nilfs_rw64(nilfsdev->super.s_last_seq);
50769a586f2Sreinoud
50869a586f2Sreinoud nilfsdev->last_seg_seq = last_seq;
50969a586f2Sreinoud nilfsdev->last_seg_num = nilfs_get_segnum_of_block(nilfsdev, last_pseg);
51069a586f2Sreinoud nilfsdev->next_seg_num = nilfs_get_segnum_of_block(nilfsdev,
51169a586f2Sreinoud nilfs_rw64(nilfsdev->last_segsum.ss_next));
51269a586f2Sreinoud nilfsdev->last_cno = last_cno;
51369a586f2Sreinoud
51469a586f2Sreinoud DPRINTF(VOLUMES, ("nilfs_mount: accepted super root\n"));
51569a586f2Sreinoud
51669a586f2Sreinoud /* create system vnodes for DAT, CP and SEGSUM */
51769a586f2Sreinoud error = nilfs_create_system_nodes(nilfsdev);
51869a586f2Sreinoud if (error)
51969a586f2Sreinoud nilfs_unmount_base(nilfsdev);
52069a586f2Sreinoud return error;
52169a586f2Sreinoud }
52269a586f2Sreinoud
52369a586f2Sreinoud
52469a586f2Sreinoud static void
nilfs_unmount_device(struct nilfs_device * nilfsdev)52569a586f2Sreinoud nilfs_unmount_device(struct nilfs_device *nilfsdev)
52669a586f2Sreinoud {
52769a586f2Sreinoud int error;
52869a586f2Sreinoud
52969a586f2Sreinoud /* is there anything? */
53069a586f2Sreinoud if (nilfsdev == NULL)
53169a586f2Sreinoud return;
53269a586f2Sreinoud
53369a586f2Sreinoud /* remove the device only if we're the last reference */
53469a586f2Sreinoud nilfsdev->refcnt--;
53569a586f2Sreinoud if (nilfsdev->refcnt >= 1)
53669a586f2Sreinoud return;
53769a586f2Sreinoud
53869a586f2Sreinoud /* unmount our base */
53969a586f2Sreinoud nilfs_unmount_base(nilfsdev);
54069a586f2Sreinoud
54169a586f2Sreinoud /* remove from our device list */
54269a586f2Sreinoud SLIST_REMOVE(&nilfs_devices, nilfsdev, nilfs_device, next_device);
54369a586f2Sreinoud
54469a586f2Sreinoud /* close device */
54569a586f2Sreinoud DPRINTF(VOLUMES, ("closing device\n"));
54669a586f2Sreinoud
54769a586f2Sreinoud /* remove our mount reference before closing device */
5483881f4f3Shannken spec_node_setmountedfs(nilfsdev->devvp, NULL);
54969a586f2Sreinoud
55069a586f2Sreinoud /* devvp is still locked by us */
55169a586f2Sreinoud vn_lock(nilfsdev->devvp, LK_EXCLUSIVE | LK_RETRY);
55269a586f2Sreinoud error = VOP_CLOSE(nilfsdev->devvp, FREAD | FWRITE, NOCRED);
55369a586f2Sreinoud if (error)
55469a586f2Sreinoud printf("Error during closure of device! error %d, "
55569a586f2Sreinoud "device might stay locked\n", error);
55669a586f2Sreinoud DPRINTF(VOLUMES, ("device close ok\n"));
55769a586f2Sreinoud
55869a586f2Sreinoud /* clear our mount reference and release device node */
55969a586f2Sreinoud vput(nilfsdev->devvp);
56069a586f2Sreinoud
56169a586f2Sreinoud /* free our device info */
56252473f33Shannken cv_destroy(&nilfsdev->sync_cv);
56369a586f2Sreinoud free(nilfsdev, M_NILFSMNT);
56469a586f2Sreinoud }
56569a586f2Sreinoud
56669a586f2Sreinoud
56769a586f2Sreinoud static int
nilfs_check_mounts(struct nilfs_device * nilfsdev,struct mount * mp,struct nilfs_args * args)56869a586f2Sreinoud nilfs_check_mounts(struct nilfs_device *nilfsdev, struct mount *mp,
56969a586f2Sreinoud struct nilfs_args *args)
57069a586f2Sreinoud {
57169a586f2Sreinoud struct nilfs_mount *ump;
57269a586f2Sreinoud uint64_t last_cno;
57369a586f2Sreinoud
57469a586f2Sreinoud /* no double-mounting of the same checkpoint */
57569a586f2Sreinoud STAILQ_FOREACH(ump, &nilfsdev->mounts, next_mount) {
57669a586f2Sreinoud if (ump->mount_args.cpno == args->cpno)
57769a586f2Sreinoud return EBUSY;
57869a586f2Sreinoud }
57969a586f2Sreinoud
58069a586f2Sreinoud /* allow readonly mounts without questioning here */
58169a586f2Sreinoud if (mp->mnt_flag & MNT_RDONLY)
58269a586f2Sreinoud return 0;
58369a586f2Sreinoud
58469a586f2Sreinoud /* readwrite mount you want */
58569a586f2Sreinoud STAILQ_FOREACH(ump, &nilfsdev->mounts, next_mount) {
58669a586f2Sreinoud /* only one RW mount on this device! */
58769a586f2Sreinoud if ((ump->vfs_mountp->mnt_flag & MNT_RDONLY)==0)
58869a586f2Sreinoud return EROFS;
58969a586f2Sreinoud /* RDONLY on last mountpoint is device busy */
59069a586f2Sreinoud last_cno = nilfs_rw64(ump->nilfsdev->super.s_last_cno);
59169a586f2Sreinoud if (ump->mount_args.cpno == last_cno)
59269a586f2Sreinoud return EBUSY;
59369a586f2Sreinoud }
59469a586f2Sreinoud
59569a586f2Sreinoud /* OK for now */
59669a586f2Sreinoud return 0;
59769a586f2Sreinoud }
59869a586f2Sreinoud
59969a586f2Sreinoud
60069a586f2Sreinoud static int
nilfs_mount_device(struct vnode * devvp,struct mount * mp,struct nilfs_args * args,struct nilfs_device ** nilfsdev_p)60169a586f2Sreinoud nilfs_mount_device(struct vnode *devvp, struct mount *mp, struct nilfs_args *args,
60269a586f2Sreinoud struct nilfs_device **nilfsdev_p)
60369a586f2Sreinoud {
6043aa8e3d3Schristos uint64_t psize;
6053aa8e3d3Schristos unsigned secsize;
60669a586f2Sreinoud struct nilfs_device *nilfsdev;
60769a586f2Sreinoud struct lwp *l = curlwp;
60869a586f2Sreinoud int openflags, accessmode, error;
60969a586f2Sreinoud
61069a586f2Sreinoud DPRINTF(VOLUMES, ("Mounting NILFS device\n"));
61169a586f2Sreinoud
61269a586f2Sreinoud /* lookup device in our nilfs_mountpoints */
61369a586f2Sreinoud *nilfsdev_p = NULL;
61469a586f2Sreinoud SLIST_FOREACH(nilfsdev, &nilfs_devices, next_device)
61569a586f2Sreinoud if (nilfsdev->devvp == devvp)
61669a586f2Sreinoud break;
61769a586f2Sreinoud
61869a586f2Sreinoud if (nilfsdev) {
61969a586f2Sreinoud DPRINTF(VOLUMES, ("device already mounted\n"));
62069a586f2Sreinoud error = nilfs_check_mounts(nilfsdev, mp, args);
62169a586f2Sreinoud if (error)
62269a586f2Sreinoud return error;
62369a586f2Sreinoud nilfsdev->refcnt++;
62469a586f2Sreinoud *nilfsdev_p = nilfsdev;
62569a586f2Sreinoud return 0;
62669a586f2Sreinoud }
62769a586f2Sreinoud
62869a586f2Sreinoud DPRINTF(VOLUMES, ("no previous mounts on this device, mounting device\n"));
62969a586f2Sreinoud
63069a586f2Sreinoud /* check if its a block device specified */
63169a586f2Sreinoud if (devvp->v_type != VBLK) {
63269a586f2Sreinoud vrele(devvp);
63369a586f2Sreinoud return ENOTBLK;
63469a586f2Sreinoud }
63569a586f2Sreinoud if (bdevsw_lookup(devvp->v_rdev) == NULL) {
63669a586f2Sreinoud vrele(devvp);
63769a586f2Sreinoud return ENXIO;
63869a586f2Sreinoud }
63969a586f2Sreinoud
64069a586f2Sreinoud /*
64169a586f2Sreinoud * If mount by non-root, then verify that user has necessary
64269a586f2Sreinoud * permissions on the device.
64369a586f2Sreinoud */
64469a586f2Sreinoud accessmode = VREAD;
64569a586f2Sreinoud if ((mp->mnt_flag & MNT_RDONLY) == 0)
64669a586f2Sreinoud accessmode |= VWRITE;
64769a586f2Sreinoud vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
6480c9d8d15Selad error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
6490c9d8d15Selad KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode));
6501423e65bShannken VOP_UNLOCK(devvp);
65169a586f2Sreinoud if (error) {
65269a586f2Sreinoud vrele(devvp);
65369a586f2Sreinoud return error;
65469a586f2Sreinoud }
65569a586f2Sreinoud
65669a586f2Sreinoud /*
65769a586f2Sreinoud * Open device read-write; TODO how about upgrading later when needed?
65869a586f2Sreinoud */
65969a586f2Sreinoud openflags = FREAD | FWRITE;
660d84a65ddShannken vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
66169a586f2Sreinoud error = VOP_OPEN(devvp, openflags, FSCRED);
662d84a65ddShannken VOP_UNLOCK(devvp);
66369a586f2Sreinoud if (error) {
66469a586f2Sreinoud vrele(devvp);
66569a586f2Sreinoud return error;
66669a586f2Sreinoud }
66769a586f2Sreinoud
66869a586f2Sreinoud /* opened ok, try mounting */
6693aa8e3d3Schristos nilfsdev = malloc(sizeof(*nilfsdev), M_NILFSMNT, M_WAITOK | M_ZERO);
67069a586f2Sreinoud
67169a586f2Sreinoud /* initialise */
67269a586f2Sreinoud nilfsdev->refcnt = 1;
67369a586f2Sreinoud nilfsdev->devvp = devvp;
67469a586f2Sreinoud nilfsdev->uncomitted_bl = 0;
6754973fb4eSpgoyette cv_init(&nilfsdev->sync_cv, "nilfssyn");
67669a586f2Sreinoud STAILQ_INIT(&nilfsdev->mounts);
67769a586f2Sreinoud
6780b69cddaSdholland /* register nilfs_device in list */
6790b69cddaSdholland SLIST_INSERT_HEAD(&nilfs_devices, nilfsdev, next_device);
6800b69cddaSdholland
68169a586f2Sreinoud /* get our device's size */
6823aa8e3d3Schristos error = getdisksize(devvp, &psize, &secsize);
68369a586f2Sreinoud if (error) {
68469a586f2Sreinoud /* remove all our information */
68569a586f2Sreinoud nilfs_unmount_device(nilfsdev);
68669a586f2Sreinoud return EINVAL;
68769a586f2Sreinoud }
6883aa8e3d3Schristos
6893aa8e3d3Schristos nilfsdev->devsize = psize * secsize;
69069a586f2Sreinoud
69169a586f2Sreinoud /* connect to the head for most recent files XXX really pass mp and args? */
69269a586f2Sreinoud error = nilfs_mount_base(nilfsdev, mp, args);
69369a586f2Sreinoud if (error) {
69469a586f2Sreinoud /* remove all our information */
69569a586f2Sreinoud nilfs_unmount_device(nilfsdev);
69669a586f2Sreinoud return EINVAL;
69769a586f2Sreinoud }
69869a586f2Sreinoud
69969a586f2Sreinoud *nilfsdev_p = nilfsdev;
70069a586f2Sreinoud DPRINTF(VOLUMES, ("NILFS device mounted ok\n"));
70169a586f2Sreinoud
70269a586f2Sreinoud return 0;
70369a586f2Sreinoud }
70469a586f2Sreinoud
70569a586f2Sreinoud
70669a586f2Sreinoud static int
nilfs_mount_checkpoint(struct nilfs_mount * ump)70769a586f2Sreinoud nilfs_mount_checkpoint(struct nilfs_mount *ump)
70869a586f2Sreinoud {
70969a586f2Sreinoud struct nilfs_cpfile_header *cphdr;
71069a586f2Sreinoud struct nilfs_checkpoint *cp;
71169a586f2Sreinoud struct nilfs_inode ifile_inode;
71269a586f2Sreinoud struct nilfs_node *cp_node;
71369a586f2Sreinoud struct buf *bp;
71469a586f2Sreinoud uint64_t ncp, nsn, fcpno, blocknr, last_cno;
71569a586f2Sreinoud uint32_t off, dlen;
71669a586f2Sreinoud int cp_per_block, error;
71769a586f2Sreinoud
71869a586f2Sreinoud DPRINTF(VOLUMES, ("mount_nilfs: trying to mount checkpoint number "
71969a586f2Sreinoud "%"PRIu64"\n", ump->mount_args.cpno));
72069a586f2Sreinoud
72169a586f2Sreinoud cp_node = ump->nilfsdev->cp_node;
72269a586f2Sreinoud
72369a586f2Sreinoud /* get cpfile header from 1st block of cp file */
7246e392401Smaxv error = nilfs_bread(cp_node, 0, 0, &bp);
72569a586f2Sreinoud if (error)
72669a586f2Sreinoud return error;
72769a586f2Sreinoud cphdr = (struct nilfs_cpfile_header *) bp->b_data;
72869a586f2Sreinoud ncp = nilfs_rw64(cphdr->ch_ncheckpoints);
72969a586f2Sreinoud nsn = nilfs_rw64(cphdr->ch_nsnapshots);
73069a586f2Sreinoud
73169a586f2Sreinoud brelse(bp, BC_AGE);
73269a586f2Sreinoud
73369a586f2Sreinoud DPRINTF(VOLUMES, ("mount_nilfs: checkpoint header read in\n"));
73469a586f2Sreinoud DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp));
73569a586f2Sreinoud DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn));
7369ec4136dSchristos #ifndef NILFS_DEBUG
7379ec4136dSchristos __USE(ncp);
7389ec4136dSchristos __USE(nsn);
7399ec4136dSchristos #endif
74069a586f2Sreinoud
74169a586f2Sreinoud /* read in our specified checkpoint */
74269a586f2Sreinoud dlen = nilfs_rw16(ump->nilfsdev->super.s_checkpoint_size);
74369a586f2Sreinoud cp_per_block = ump->nilfsdev->blocksize / dlen;
74469a586f2Sreinoud
74569a586f2Sreinoud fcpno = ump->mount_args.cpno + NILFS_CPFILE_FIRST_CHECKPOINT_OFFSET -1;
74669a586f2Sreinoud blocknr = fcpno / cp_per_block;
74769a586f2Sreinoud off = (fcpno % cp_per_block) * dlen;
74869a586f2Sreinoud
7496e392401Smaxv error = nilfs_bread(cp_node, blocknr, 0, &bp);
75069a586f2Sreinoud if (error) {
75169a586f2Sreinoud printf("mount_nilfs: couldn't read cp block %"PRIu64"\n",
75269a586f2Sreinoud fcpno);
75369a586f2Sreinoud return EINVAL;
75469a586f2Sreinoud }
75569a586f2Sreinoud
75669a586f2Sreinoud /* needs to be a valid checkpoint */
75769a586f2Sreinoud cp = (struct nilfs_checkpoint *) ((uint8_t *) bp->b_data + off);
75869a586f2Sreinoud if (cp->cp_flags & NILFS_CHECKPOINT_INVALID) {
75969a586f2Sreinoud printf("mount_nilfs: checkpoint marked invalid\n");
76069a586f2Sreinoud brelse(bp, BC_AGE);
76169a586f2Sreinoud return EINVAL;
76269a586f2Sreinoud }
76369a586f2Sreinoud
76469a586f2Sreinoud /* is this really the checkpoint we want? */
76569a586f2Sreinoud if (nilfs_rw64(cp->cp_cno) != ump->mount_args.cpno) {
76669a586f2Sreinoud printf("mount_nilfs: checkpoint file corrupt? "
76769a586f2Sreinoud "expected cpno %"PRIu64", found cpno %"PRIu64"\n",
76869a586f2Sreinoud ump->mount_args.cpno, nilfs_rw64(cp->cp_cno));
76969a586f2Sreinoud brelse(bp, BC_AGE);
77069a586f2Sreinoud return EINVAL;
77169a586f2Sreinoud }
77269a586f2Sreinoud
77369a586f2Sreinoud /* check if its a snapshot ! */
77469a586f2Sreinoud last_cno = nilfs_rw64(ump->nilfsdev->super.s_last_cno);
77569a586f2Sreinoud if (ump->mount_args.cpno != last_cno) {
77669a586f2Sreinoud /* only allow snapshots if not mounting on the last cp */
77769a586f2Sreinoud if ((cp->cp_flags & NILFS_CHECKPOINT_SNAPSHOT) == 0) {
77869a586f2Sreinoud printf( "mount_nilfs: checkpoint %"PRIu64" is not a "
77969a586f2Sreinoud "snapshot\n", ump->mount_args.cpno);
78069a586f2Sreinoud brelse(bp, BC_AGE);
78169a586f2Sreinoud return EINVAL;
78269a586f2Sreinoud }
78369a586f2Sreinoud }
78469a586f2Sreinoud
78569a586f2Sreinoud ifile_inode = cp->cp_ifile_inode;
78669a586f2Sreinoud brelse(bp, BC_AGE);
78769a586f2Sreinoud
78869a586f2Sreinoud /* get ifile inode */
78969a586f2Sreinoud error = nilfs_get_node_raw(ump->nilfsdev, NULL, NILFS_IFILE_INO,
79069a586f2Sreinoud &ifile_inode, &ump->ifile_node);
79169a586f2Sreinoud if (error) {
79269a586f2Sreinoud printf("mount_nilfs: can't read ifile node\n");
79369a586f2Sreinoud return EINVAL;
79469a586f2Sreinoud }
79569a586f2Sreinoud
79669a586f2Sreinoud /* get root node? */
79769a586f2Sreinoud
79869a586f2Sreinoud return 0;
79969a586f2Sreinoud }
80069a586f2Sreinoud
80169a586f2Sreinoud
80269a586f2Sreinoud static int
nilfs_stop_writing(struct nilfs_mount * ump)80369a586f2Sreinoud nilfs_stop_writing(struct nilfs_mount *ump)
80469a586f2Sreinoud {
80569a586f2Sreinoud /* readonly mounts won't write */
80669a586f2Sreinoud if (ump->vfs_mountp->mnt_flag & MNT_RDONLY)
80769a586f2Sreinoud return 0;
80869a586f2Sreinoud
80969a586f2Sreinoud DPRINTF(CALL, ("nilfs_stop_writing called for RW mount\n"));
81069a586f2Sreinoud
81169a586f2Sreinoud /* TODO writeout super_block? */
81269a586f2Sreinoud /* XXX no support for writing yet anyway */
81369a586f2Sreinoud return 0;
81469a586f2Sreinoud }
81569a586f2Sreinoud
81669a586f2Sreinoud
81769a586f2Sreinoud /* --------------------------------------------------------------------- */
81869a586f2Sreinoud
81969a586f2Sreinoud
82069a586f2Sreinoud
82169a586f2Sreinoud #define MPFREE(a, lst) \
82269a586f2Sreinoud if ((a)) free((a), lst);
82369a586f2Sreinoud static void
free_nilfs_mountinfo(struct mount * mp)82469a586f2Sreinoud free_nilfs_mountinfo(struct mount *mp)
82569a586f2Sreinoud {
82669a586f2Sreinoud struct nilfs_mount *ump = VFSTONILFS(mp);
82769a586f2Sreinoud
82869a586f2Sreinoud if (ump == NULL)
82969a586f2Sreinoud return;
83069a586f2Sreinoud
83169a586f2Sreinoud MPFREE(ump, M_NILFSMNT);
83269a586f2Sreinoud }
83369a586f2Sreinoud #undef MPFREE
83469a586f2Sreinoud
83569a586f2Sreinoud int
nilfs_mount(struct mount * mp,const char * path,void * data,size_t * data_len)83669a586f2Sreinoud nilfs_mount(struct mount *mp, const char *path,
83769a586f2Sreinoud void *data, size_t *data_len)
83869a586f2Sreinoud {
83969a586f2Sreinoud struct nilfs_args *args = data;
84069a586f2Sreinoud struct nilfs_device *nilfsdev;
84169a586f2Sreinoud struct nilfs_mount *ump;
84269a586f2Sreinoud struct vnode *devvp;
843668c7daaShannken int error;
84469a586f2Sreinoud
84569a586f2Sreinoud DPRINTF(VFSCALL, ("nilfs_mount called\n"));
84669a586f2Sreinoud
84723f76b6dSmaxv if (args == NULL)
84823f76b6dSmaxv return EINVAL;
84969a586f2Sreinoud if (*data_len < sizeof *args)
85069a586f2Sreinoud return EINVAL;
85169a586f2Sreinoud
85269a586f2Sreinoud if (mp->mnt_flag & MNT_GETARGS) {
85369a586f2Sreinoud /* request for the mount arguments */
85469a586f2Sreinoud ump = VFSTONILFS(mp);
85569a586f2Sreinoud if (ump == NULL)
85669a586f2Sreinoud return EINVAL;
85769a586f2Sreinoud *args = ump->mount_args;
85869a586f2Sreinoud *data_len = sizeof *args;
85969a586f2Sreinoud return 0;
86069a586f2Sreinoud }
86169a586f2Sreinoud
86269a586f2Sreinoud /* check/translate struct version */
86369a586f2Sreinoud if (args->version != 1) {
86469a586f2Sreinoud printf("mount_nilfs: unrecognized argument structure version\n");
86569a586f2Sreinoud return EINVAL;
86669a586f2Sreinoud }
86769a586f2Sreinoud /* TODO sanity checking other mount arguments */
86869a586f2Sreinoud
86969a586f2Sreinoud /* handle request for updating mount parameters */
87069a586f2Sreinoud if (mp->mnt_flag & MNT_UPDATE) {
87169a586f2Sreinoud /* TODO can't update my mountpoint yet */
87269a586f2Sreinoud return EOPNOTSUPP;
87369a586f2Sreinoud }
87469a586f2Sreinoud
87569a586f2Sreinoud /* lookup name to get its vnode */
87669a586f2Sreinoud error = namei_simple_user(args->fspec, NSM_FOLLOW_NOEMULROOT, &devvp);
87769a586f2Sreinoud if (error)
87869a586f2Sreinoud return error;
87969a586f2Sreinoud
88069a586f2Sreinoud #ifdef DEBUG
88169a586f2Sreinoud if (nilfs_verbose & NILFS_DEBUG_VOLUMES)
88269a586f2Sreinoud vprint("NILFS mount, trying to mount \n", devvp);
88369a586f2Sreinoud #endif
88469a586f2Sreinoud
88569a586f2Sreinoud error = nilfs_mount_device(devvp, mp, args, &nilfsdev);
88640e39321Smaxv if (error)
88769a586f2Sreinoud return error;
88869a586f2Sreinoud
88969a586f2Sreinoud /*
89069a586f2Sreinoud * Create a nilfs_mount on the specified checkpoint. Note that only
89169a586f2Sreinoud * ONE RW mount point can exist and it needs to have the highest
89269a586f2Sreinoud * checkpoint nr. If mounting RW and its not on the last checkpoint we
89369a586f2Sreinoud * need to invalidate all checkpoints that follow!!! This is an
89469a586f2Sreinoud * advanced option.
89569a586f2Sreinoud */
89669a586f2Sreinoud
89769a586f2Sreinoud /* setup basic mountpoint structure */
89869a586f2Sreinoud mp->mnt_data = NULL;
89969a586f2Sreinoud mp->mnt_stat.f_fsidx.__fsid_val[0] = (uint32_t) devvp->v_rdev;
90069a586f2Sreinoud mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_NILFS);
90169a586f2Sreinoud mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
90269a586f2Sreinoud mp->mnt_stat.f_namemax = NILFS_NAME_LEN;
90369a586f2Sreinoud mp->mnt_flag |= MNT_LOCAL;
90469a586f2Sreinoud
90569a586f2Sreinoud /* XXX can't enable MPSAFE yet since genfs barfs on bad CV */
90669a586f2Sreinoud // mp->mnt_iflag |= IMNT_MPSAFE;
90769a586f2Sreinoud
90869a586f2Sreinoud /* set our dev and fs units */
90969a586f2Sreinoud mp->mnt_dev_bshift = nilfs_rw32(nilfsdev->super.s_log_block_size) + 10;
91069a586f2Sreinoud mp->mnt_fs_bshift = mp->mnt_dev_bshift;
91169a586f2Sreinoud
91269a586f2Sreinoud /* allocate nilfs part of mount structure; malloc always succeeds */
91369a586f2Sreinoud ump = malloc(sizeof(struct nilfs_mount), M_NILFSMNT, M_WAITOK | M_ZERO);
91469a586f2Sreinoud
91569a586f2Sreinoud /* set up linkage */
91669a586f2Sreinoud mp->mnt_data = ump;
91769a586f2Sreinoud ump->vfs_mountp = mp;
91869a586f2Sreinoud ump->nilfsdev = nilfsdev;
91969a586f2Sreinoud
92069a586f2Sreinoud #if 0
92169a586f2Sreinoud #ifndef NILFS_READWRITE
92269a586f2Sreinoud /* force read-only for now */
92369a586f2Sreinoud if ((mp->mnt_flag & MNT_RDONLY) == 0) {
92469a586f2Sreinoud printf( "Enable kernel/module option NILFS_READWRITE for "
92569a586f2Sreinoud "writing, downgrading access to read-only\n");
92669a586f2Sreinoud mp->mnt_flag |= MNT_RDONLY;
92769a586f2Sreinoud }
92869a586f2Sreinoud #endif
92969a586f2Sreinoud #endif
93069a586f2Sreinoud
93169a586f2Sreinoud /* DONT register our nilfs mountpoint on our vfs mountpoint */
9323881f4f3Shannken spec_node_setmountedfs(devvp, NULL);
93369a586f2Sreinoud #if 0
9343881f4f3Shannken if (spec_node_getmountedfs(devvp) == NULL)
9353881f4f3Shannken spec_node_setmountedfs(devvp, mp);
93669a586f2Sreinoud if ((mp->mnt_flag & MNT_RDONLY) == 0)
9373881f4f3Shannken spec_node_setmountedfs(devvp, mp);
93869a586f2Sreinoud #endif
93969a586f2Sreinoud
94069a586f2Sreinoud /* add our mountpoint */
94169a586f2Sreinoud STAILQ_INSERT_TAIL(&nilfsdev->mounts, ump, next_mount);
94269a586f2Sreinoud
94369a586f2Sreinoud /* get our selected checkpoint */
94469a586f2Sreinoud if (args->cpno == 0)
94569a586f2Sreinoud args->cpno = nilfsdev->last_cno;
94669a586f2Sreinoud args->cpno = MIN(args->cpno, nilfsdev->last_cno);
94769a586f2Sreinoud
94869a586f2Sreinoud /* setting up other parameters */
94969a586f2Sreinoud ump->mount_args = *args;
95069a586f2Sreinoud error = nilfs_mount_checkpoint(ump);
95169a586f2Sreinoud if (error) {
95269a586f2Sreinoud nilfs_unmount(mp, MNT_FORCE);
95369a586f2Sreinoud return error;
95469a586f2Sreinoud }
95569a586f2Sreinoud
95669a586f2Sreinoud /* set VFS info */
95769a586f2Sreinoud error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
95869a586f2Sreinoud mp->mnt_op->vfs_name, mp, curlwp);
95969a586f2Sreinoud if (error) {
96069a586f2Sreinoud nilfs_unmount(mp, MNT_FORCE);
96169a586f2Sreinoud return error;
96269a586f2Sreinoud }
96369a586f2Sreinoud
96469a586f2Sreinoud /* successfully mounted */
965*b5860281Sandvar DPRINTF(VOLUMES, ("nilfs_mount() successful\n"));
96669a586f2Sreinoud
96769a586f2Sreinoud return 0;
96869a586f2Sreinoud }
96969a586f2Sreinoud
97069a586f2Sreinoud /* --------------------------------------------------------------------- */
97169a586f2Sreinoud
97269a586f2Sreinoud
97369a586f2Sreinoud /* remove our mountpoint and if its the last reference, remove our device */
97469a586f2Sreinoud int
nilfs_unmount(struct mount * mp,int mntflags)97569a586f2Sreinoud nilfs_unmount(struct mount *mp, int mntflags)
97669a586f2Sreinoud {
97769a586f2Sreinoud struct nilfs_device *nilfsdev;
97869a586f2Sreinoud struct nilfs_mount *ump;
97969a586f2Sreinoud int error, flags;
98069a586f2Sreinoud
98169a586f2Sreinoud DPRINTF(VFSCALL, ("nilfs_umount called\n"));
98269a586f2Sreinoud
98369a586f2Sreinoud ump = VFSTONILFS(mp);
98469a586f2Sreinoud if (!ump)
98569a586f2Sreinoud panic("NILFS unmount: empty ump\n");
98669a586f2Sreinoud nilfsdev = ump->nilfsdev;
98769a586f2Sreinoud
98869a586f2Sreinoud /*
98952473f33Shannken * Flush all nodes associated to this mountpoint.
99069a586f2Sreinoud */
99169a586f2Sreinoud flags = (mntflags & MNT_FORCE) ? FORCECLOSE : 0;
99252473f33Shannken if ((error = vflush(mp, NULLVP, flags)) != 0)
99369a586f2Sreinoud return error;
99469a586f2Sreinoud
99569a586f2Sreinoud /* if we're the write mount, we ought to close the writing session */
99669a586f2Sreinoud error = nilfs_stop_writing(ump);
99769a586f2Sreinoud if (error)
99869a586f2Sreinoud return error;
99969a586f2Sreinoud
100069a586f2Sreinoud nilfs_dispose_node(&ump->ifile_node);
100169a586f2Sreinoud
100269a586f2Sreinoud /* remove our mount point */
100369a586f2Sreinoud STAILQ_REMOVE(&nilfsdev->mounts, ump, nilfs_mount, next_mount);
100469a586f2Sreinoud free_nilfs_mountinfo(mp);
100569a586f2Sreinoud
100669a586f2Sreinoud /* free ump struct references */
100769a586f2Sreinoud mp->mnt_data = NULL;
100869a586f2Sreinoud mp->mnt_flag &= ~MNT_LOCAL;
100969a586f2Sreinoud
101069a586f2Sreinoud /* unmount the device itself when we're the last one */
101169a586f2Sreinoud nilfs_unmount_device(nilfsdev);
101269a586f2Sreinoud
101369a586f2Sreinoud DPRINTF(VOLUMES, ("Fin unmount\n"));
101469a586f2Sreinoud return error;
101569a586f2Sreinoud }
101669a586f2Sreinoud
101769a586f2Sreinoud /* --------------------------------------------------------------------- */
101869a586f2Sreinoud
101969a586f2Sreinoud int
nilfs_start(struct mount * mp,int flags)102069a586f2Sreinoud nilfs_start(struct mount *mp, int flags)
102169a586f2Sreinoud {
102269a586f2Sreinoud /* do we have to do something here? */
102369a586f2Sreinoud return 0;
102469a586f2Sreinoud }
102569a586f2Sreinoud
102669a586f2Sreinoud /* --------------------------------------------------------------------- */
102769a586f2Sreinoud
102869a586f2Sreinoud int
nilfs_root(struct mount * mp,int lktype,struct vnode ** vpp)1029c2e9cb94Sad nilfs_root(struct mount *mp, int lktype, struct vnode **vpp)
103069a586f2Sreinoud {
1031668c7daaShannken uint64_t ino = NILFS_ROOT_INO;
103269a586f2Sreinoud int error;
103369a586f2Sreinoud
103469a586f2Sreinoud DPRINTF(NODE, ("nilfs_root called\n"));
103569a586f2Sreinoud
1036668c7daaShannken error = vcache_get(mp, &ino, sizeof(ino), vpp);
103752473f33Shannken if (error == 0) {
1038c2e9cb94Sad error = vn_lock(*vpp, lktype);
103952473f33Shannken if (error) {
104052473f33Shannken vrele(*vpp);
104152473f33Shannken *vpp = NULL;
104252473f33Shannken return error;
104369a586f2Sreinoud }
104452473f33Shannken }
104552473f33Shannken KASSERT(error != 0 || ((*vpp)->v_vflag & VV_ROOT));
104669a586f2Sreinoud
104769a586f2Sreinoud DPRINTF(NODE, ("nilfs_root finished\n"));
104869a586f2Sreinoud return error;
104969a586f2Sreinoud }
105069a586f2Sreinoud
105169a586f2Sreinoud /* --------------------------------------------------------------------- */
105269a586f2Sreinoud
105369a586f2Sreinoud int
nilfs_statvfs(struct mount * mp,struct statvfs * sbp)105469a586f2Sreinoud nilfs_statvfs(struct mount *mp, struct statvfs *sbp)
105569a586f2Sreinoud {
105669a586f2Sreinoud struct nilfs_mount *ump = VFSTONILFS(mp);
105769a586f2Sreinoud uint32_t blocksize;
105869a586f2Sreinoud
105969a586f2Sreinoud DPRINTF(VFSCALL, ("nilfs_statvfs called\n"));
106069a586f2Sreinoud
106169a586f2Sreinoud blocksize = ump->nilfsdev->blocksize;
106269a586f2Sreinoud sbp->f_flag = mp->mnt_flag;
106369a586f2Sreinoud sbp->f_bsize = blocksize;
106469a586f2Sreinoud sbp->f_frsize = blocksize;
106569a586f2Sreinoud sbp->f_iosize = blocksize;
106669a586f2Sreinoud
106769a586f2Sreinoud copy_statvfs_info(sbp, mp);
106869a586f2Sreinoud return 0;
106969a586f2Sreinoud }
107069a586f2Sreinoud
107169a586f2Sreinoud /* --------------------------------------------------------------------- */
107269a586f2Sreinoud
107369a586f2Sreinoud int
nilfs_sync(struct mount * mp,int waitfor,kauth_cred_t cred)107469a586f2Sreinoud nilfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
107569a586f2Sreinoud {
107669a586f2Sreinoud // struct nilfs_mount *ump = VFSTONILFS(mp);
107769a586f2Sreinoud
107869a586f2Sreinoud DPRINTF(VFSCALL, ("nilfs_sync called\n"));
107969a586f2Sreinoud /* if called when mounted readonly, just ignore */
108069a586f2Sreinoud if (mp->mnt_flag & MNT_RDONLY)
108169a586f2Sreinoud return 0;
108269a586f2Sreinoud
108369a586f2Sreinoud DPRINTF(VFSCALL, ("end of nilfs_sync()\n"));
108469a586f2Sreinoud
108569a586f2Sreinoud return 0;
108669a586f2Sreinoud }
108769a586f2Sreinoud
108869a586f2Sreinoud /* --------------------------------------------------------------------- */
108969a586f2Sreinoud
109069a586f2Sreinoud /*
109169a586f2Sreinoud * Get vnode for the file system type specific file id ino for the fs. Its
109269a586f2Sreinoud * used for reference to files by unique ID and for NFSv3.
109369a586f2Sreinoud * (optional) TODO lookup why some sources state NFSv3
109469a586f2Sreinoud */
109569a586f2Sreinoud int
nilfs_vget(struct mount * mp,ino_t ino,int lktype,struct vnode ** vpp)1096c2e9cb94Sad nilfs_vget(struct mount *mp, ino_t ino, int lktype,
109769a586f2Sreinoud struct vnode **vpp)
109869a586f2Sreinoud {
109969a586f2Sreinoud DPRINTF(NOTIMPL, ("nilfs_vget called\n"));
110069a586f2Sreinoud return EOPNOTSUPP;
110169a586f2Sreinoud }
110269a586f2Sreinoud
110369a586f2Sreinoud /* --------------------------------------------------------------------- */
110469a586f2Sreinoud
110569a586f2Sreinoud /*
1106668c7daaShannken * Read an inode from disk and initialize this vnode / inode pair.
1107668c7daaShannken * Caller assures no other thread will try to load this inode.
1108668c7daaShannken */
1109668c7daaShannken int
nilfs_loadvnode(struct mount * mp,struct vnode * vp,const void * key,size_t key_len,const void ** new_key)1110668c7daaShannken nilfs_loadvnode(struct mount *mp, struct vnode *vp,
1111668c7daaShannken const void *key, size_t key_len, const void **new_key)
1112668c7daaShannken {
1113668c7daaShannken uint64_t ino;
1114668c7daaShannken struct nilfs_device *nilfsdev;
1115668c7daaShannken struct nilfs_inode inode, *entry;
1116668c7daaShannken struct nilfs_node *node;
1117668c7daaShannken struct nilfs_mount *ump;
1118668c7daaShannken struct buf *bp;
1119668c7daaShannken uint64_t ivblocknr;
1120668c7daaShannken uint32_t entry_in_block;
1121668c7daaShannken int error;
1122668c7daaShannken extern int (**nilfs_vnodeop_p)(void *);
1123668c7daaShannken
1124668c7daaShannken KASSERT(key_len == sizeof(ino));
1125668c7daaShannken memcpy(&ino, key, key_len);
1126668c7daaShannken
1127668c7daaShannken ump = VFSTONILFS(mp);
1128668c7daaShannken
1129668c7daaShannken /* create new inode; XXX check could be handier */
1130668c7daaShannken if ((ino < NILFS_USER_INO) && (ino != NILFS_ROOT_INO)) {
1131668c7daaShannken printf("nilfs_get_node: system ino %"PRIu64" not in mount "
1132668c7daaShannken "point!\n", ino);
1133668c7daaShannken return ENOENT;
1134668c7daaShannken }
1135668c7daaShannken
1136668c7daaShannken /* lookup inode in the ifile */
1137668c7daaShannken DPRINTF(NODE, ("lookup ino %"PRIu64"\n", ino));
1138668c7daaShannken
1139668c7daaShannken /* lookup inode structure in mountpoints ifile */
1140668c7daaShannken nilfsdev = ump->nilfsdev;
1141668c7daaShannken nilfs_mdt_trans(&nilfsdev->ifile_mdt, ino, &ivblocknr, &entry_in_block);
1142668c7daaShannken
11436e392401Smaxv error = nilfs_bread(ump->ifile_node, ivblocknr, 0, &bp);
1144668c7daaShannken if (error)
1145668c7daaShannken return ENOENT;
1146668c7daaShannken
1147668c7daaShannken /* get inode entry */
1148668c7daaShannken entry = (struct nilfs_inode *) bp->b_data + entry_in_block;
1149668c7daaShannken inode = *entry;
1150668c7daaShannken brelse(bp, BC_AGE);
1151668c7daaShannken
1152668c7daaShannken /* get node */
1153668c7daaShannken error = nilfs_get_node_raw(ump->nilfsdev, ump, ino, &inode, &node);
1154668c7daaShannken if (error)
1155668c7daaShannken return error;
1156668c7daaShannken
1157668c7daaShannken vp->v_type = IFTOVT(inode.i_mode);
1158668c7daaShannken switch (vp->v_type) {
1159668c7daaShannken case VREG:
1160668c7daaShannken case VDIR:
1161668c7daaShannken case VLNK:
1162668c7daaShannken break;
1163668c7daaShannken /* other types not yet supported. */
1164668c7daaShannken default:
1165668c7daaShannken vp->v_type = VNON;
1166668c7daaShannken nilfs_dispose_node(&node);
1167668c7daaShannken return ENXIO;
1168668c7daaShannken }
1169668c7daaShannken
1170668c7daaShannken vp->v_tag = VT_NILFS;
1171668c7daaShannken vp->v_op = nilfs_vnodeop_p;
1172668c7daaShannken vp->v_data = node;
1173668c7daaShannken node->vnode = vp;
1174668c7daaShannken
1175668c7daaShannken /* initialise genfs */
1176668c7daaShannken genfs_node_init(vp, &nilfs_genfsops);
1177668c7daaShannken
1178668c7daaShannken /* check if we're fetching the root */
1179668c7daaShannken if (ino == NILFS_ROOT_INO)
1180668c7daaShannken vp->v_vflag |= VV_ROOT;
1181668c7daaShannken
1182668c7daaShannken uvm_vnp_setsize(vp, nilfs_rw64(inode.i_size));
1183668c7daaShannken *new_key = &node->ino;
1184668c7daaShannken
1185668c7daaShannken return 0;
1186668c7daaShannken
1187668c7daaShannken }
1188668c7daaShannken
1189668c7daaShannken /* --------------------------------------------------------------------- */
1190668c7daaShannken
1191668c7daaShannken /*
119269a586f2Sreinoud * Lookup vnode for file handle specified
119369a586f2Sreinoud */
119469a586f2Sreinoud int
nilfs_fhtovp(struct mount * mp,struct fid * fhp,int lktype,struct vnode ** vpp)1195c2e9cb94Sad nilfs_fhtovp(struct mount *mp, struct fid *fhp, int lktype,
119669a586f2Sreinoud struct vnode **vpp)
119769a586f2Sreinoud {
119869a586f2Sreinoud DPRINTF(NOTIMPL, ("nilfs_fhtovp called\n"));
119969a586f2Sreinoud return EOPNOTSUPP;
120069a586f2Sreinoud }
120169a586f2Sreinoud
120269a586f2Sreinoud /* --------------------------------------------------------------------- */
120369a586f2Sreinoud
120469a586f2Sreinoud /*
120569a586f2Sreinoud * Create an unique file handle. Its structure is opaque and won't be used by
120669a586f2Sreinoud * other subsystems. It should uniquely identify the file in the filingsystem
120769a586f2Sreinoud * and enough information to know if a file has been removed and/or resources
120869a586f2Sreinoud * have been recycled.
120969a586f2Sreinoud */
121069a586f2Sreinoud int
nilfs_vptofh(struct vnode * vp,struct fid * fid,size_t * fh_size)121169a586f2Sreinoud nilfs_vptofh(struct vnode *vp, struct fid *fid,
121269a586f2Sreinoud size_t *fh_size)
121369a586f2Sreinoud {
121469a586f2Sreinoud DPRINTF(NOTIMPL, ("nilfs_vptofh called\n"));
121569a586f2Sreinoud return EOPNOTSUPP;
121669a586f2Sreinoud }
121769a586f2Sreinoud
121869a586f2Sreinoud /* --------------------------------------------------------------------- */
121969a586f2Sreinoud
122069a586f2Sreinoud /*
122169a586f2Sreinoud * Create a file system snapshot at the specified timestamp.
122269a586f2Sreinoud */
122369a586f2Sreinoud int
nilfs_snapshot(struct mount * mp,struct vnode * vp,struct timespec * tm)122469a586f2Sreinoud nilfs_snapshot(struct mount *mp, struct vnode *vp,
122569a586f2Sreinoud struct timespec *tm)
122669a586f2Sreinoud {
122769a586f2Sreinoud DPRINTF(NOTIMPL, ("nilfs_snapshot called\n"));
122869a586f2Sreinoud return EOPNOTSUPP;
122969a586f2Sreinoud }
123069a586f2Sreinoud
123169a586f2Sreinoud /* --------------------------------------------------------------------- */
1232