diff options
Diffstat (limited to 'sys/gnu/reiserfs/reiserfs_vfsops.c')
-rw-r--r-- | sys/gnu/reiserfs/reiserfs_vfsops.c | 1186 |
1 files changed, 0 insertions, 1186 deletions
diff --git a/sys/gnu/reiserfs/reiserfs_vfsops.c b/sys/gnu/reiserfs/reiserfs_vfsops.c deleted file mode 100644 index 40675fc..0000000 --- a/sys/gnu/reiserfs/reiserfs_vfsops.c +++ /dev/null @@ -1,1186 +0,0 @@ -/*- - * Copyright 2000 Hans Reiser - * See README for licensing and copyright details - * - * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr> - * - * $FreeBSD$ - */ - -#include <gnu/reiserfs/reiserfs_fs.h> - -const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING; -const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING; -const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING; - -/* - * Default recommended I/O size is 128k. There might be broken - * applications that are confused by this. Use nolargeio mount option to - * get usual i/o size = PAGE_SIZE. - */ -int reiserfs_default_io_size = 128 * 1024; - -static vfs_cmount_t reiserfs_cmount; -static vfs_fhtovp_t reiserfs_fhtovp; -static vfs_mount_t reiserfs_mount; -static vfs_root_t reiserfs_root; -static vfs_statfs_t reiserfs_statfs; -static vfs_unmount_t reiserfs_unmount; -static vfs_vptofh_t reiserfs_vptofh; - -static int reiserfs_mountfs(struct vnode *devvp, struct mount *mp, - struct thread *td); -static void load_bitmap_info_data(struct reiserfs_sb_info *sbi, - struct reiserfs_bitmap_info *bi); -static int read_bitmaps(struct reiserfs_mount *rmp); -static int read_old_bitmaps(struct reiserfs_mount *rmp); -static int read_super_block(struct reiserfs_mount *rmp, int offset); -static hashf_t hash_function(struct reiserfs_mount *rmp); - -static int get_root_node(struct reiserfs_mount *rmp, - struct reiserfs_node **root); -uint32_t find_hash_out(struct reiserfs_mount *rmp); - -MALLOC_DEFINE(M_REISERFSMNT, "ReiserFS mount", "ReiserFS mount structure"); -MALLOC_DEFINE(M_REISERFSPATH, "ReiserFS path", "ReiserFS path structure"); -MALLOC_DEFINE(M_REISERFSNODE, "ReiserFS node", "ReiserFS vnode private part"); - -/* ------------------------------------------------------------------- - * VFS operations - * -------------------------------------------------------------------*/ - -static int -reiserfs_cmount(struct mntarg *ma, void *data, int flags, struct thread *td) -{ - struct reiserfs_args args; - int error; - - error = copyin(data, &args, sizeof(args)); - if (error) - return (error); - - ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &args.export, sizeof args.export); - - error = kernel_mount(ma, flags); - - return (error); -} - -/* - * Mount system call - */ -static int -reiserfs_mount(struct mount *mp, struct thread *td) -{ - size_t size; - int error, len; - mode_t accessmode; - char *path, *fspec; - struct vnode *devvp; - struct vfsoptlist *opts; - struct export_args *export; - struct reiserfs_mount *rmp; - struct reiserfs_sb_info *sbi; - struct nameidata nd, *ndp = &nd; - - if (!(mp->mnt_flag & MNT_RDONLY)) - return EROFS; - - /* Get the new options passed to mount */ - opts = mp->mnt_optnew; - - /* `fspath' contains the mount point (eg. /mnt/linux); REQUIRED */ - vfs_getopt(opts, "fspath", (void **)&path, NULL); - reiserfs_log(LOG_INFO, "mount point is `%s'\n", path); - - /* `from' contains the device name (eg. /dev/ad0s1); REQUIRED */ - fspec = NULL; - error = vfs_getopt(opts, "from", (void **)&fspec, &len); - if (!error && fspec[len - 1] != '\0') - return (EINVAL); - reiserfs_log(LOG_INFO, "device is `%s'\n", fspec); - - /* Handle MNT_UPDATE (mp->mnt_flag) */ - if (mp->mnt_flag & MNT_UPDATE) { - /* For now, only NFS export is supported. */ - error = vfs_getopt(opts, "export", (void **)&export, &len); - if (error == 0 && len == sizeof(*export) && export->ex_flags) - return (vfs_export(mp, export)); - } - - /* Not an update, or updating the name: look up the name - * and verify that it refers to a sensible disk device. */ - if (fspec == NULL) - return (EINVAL); - - NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td); - if ((error = namei(ndp)) != 0) - return (error); - NDFREE(ndp, NDF_ONLY_PNBUF); - devvp = ndp->ni_vp; - - if (!vn_isdisk(devvp, &error)) { - vrele(devvp); - return (error); - } - - /* If mount by non-root, then verify that user has necessary - * permissions on the device. */ - if (suser(td)) { - accessmode = VREAD; - if ((mp->mnt_flag & MNT_RDONLY) == 0) - accessmode |= VWRITE; - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); - if ((error = VOP_ACCESS(devvp, - accessmode, td->td_ucred, td)) != 0) { - vput(devvp); - return (error); - } - VOP_UNLOCK(devvp, 0, td); - } - - if ((mp->mnt_flag & MNT_UPDATE) == 0) { - error = reiserfs_mountfs(devvp, mp, td); - } else { - /* TODO Handle MNT_UPDATE */ - error = (EOPNOTSUPP); - } - - if (error) { - vrele(devvp); - return (error); - } - - rmp = VFSTOREISERFS(mp); - sbi = rmp->rm_reiserfs; - - /* - * Note that this strncpy() is ok because of a check at the start - * of reiserfs_mount(). - */ - reiserfs_log(LOG_DEBUG, "prepare statfs data\n"); - (void)copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - (void)reiserfs_statfs(mp, &mp->mnt_stat, td); - - reiserfs_log(LOG_DEBUG, "done\n"); - return (0); -} - -/* - * Unmount system call - */ -static int -reiserfs_unmount(struct mount *mp, int mntflags, struct thread *td) -{ - int error, flags = 0; - struct reiserfs_mount *rmp; - struct reiserfs_sb_info *sbi; - - reiserfs_log(LOG_DEBUG, "get private data\n"); - rmp = VFSTOREISERFS(mp); - sbi = rmp->rm_reiserfs; - - /* Flangs handling */ - reiserfs_log(LOG_DEBUG, "handle mntflags\n"); - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; - - /* Flush files -> vflush */ - reiserfs_log(LOG_DEBUG, "flush vnodes\n"); - if ((error = vflush(mp, 0, flags, td))) - return (error); - - /* XXX Super block update */ - - if (sbi) { - if (SB_AP_BITMAP(sbi)) { - int i; - reiserfs_log(LOG_DEBUG, - "release bitmap buffers (total: %d)\n", - SB_BMAP_NR(sbi)); - for (i = 0; i < SB_BMAP_NR(sbi); i++) { - if (SB_AP_BITMAP(sbi)[i].bp_data) { - free(SB_AP_BITMAP(sbi)[i].bp_data, - M_REISERFSMNT); - SB_AP_BITMAP(sbi)[i].bp_data = NULL; - } - } - - reiserfs_log(LOG_DEBUG, "free bitmaps structure\n"); - free(SB_AP_BITMAP(sbi), M_REISERFSMNT); - SB_AP_BITMAP(sbi) = NULL; - } - - if (sbi->s_rs) { - reiserfs_log(LOG_DEBUG, "free super block data\n"); - free(sbi->s_rs, M_REISERFSMNT); - sbi->s_rs = NULL; - } - } - - reiserfs_log(LOG_DEBUG, "close device\n"); -#if defined(si_mountpoint) - rmp->rm_devvp->v_rdev->si_mountpoint = NULL; -#endif - - DROP_GIANT(); - g_topology_lock(); - g_wither_geom_close(rmp->rm_cp->geom, ENXIO); - g_topology_unlock(); - PICKUP_GIANT(); - vrele(rmp->rm_devvp); - - if (sbi) { - reiserfs_log(LOG_DEBUG, "free sbi\n"); - free(sbi, M_REISERFSMNT); - sbi = rmp->rm_reiserfs = NULL; - } - if (rmp) { - reiserfs_log(LOG_DEBUG, "free rmp\n"); - free(rmp, M_REISERFSMNT); - rmp = NULL; - } - - mp->mnt_data = (qaddr_t)0; - mp->mnt_flag &= ~MNT_LOCAL; - - reiserfs_log(LOG_DEBUG, "done\n"); - return (error); -} - -/* - * Return the root of a filesystem. - */ -static int -reiserfs_root(struct mount *mp, int flags, struct vnode **vpp, - struct thread *td) -{ - int error; - struct vnode *vp; - struct cpu_key rootkey; - - rootkey.on_disk_key.k_dir_id = REISERFS_ROOT_PARENT_OBJECTID; - rootkey.on_disk_key.k_objectid = REISERFS_ROOT_OBJECTID; - - error = reiserfs_iget(mp, &rootkey, &vp, td); - - if (error == 0) - *vpp = vp; - return (error); -} - -/* - * The statfs syscall - */ -static int -reiserfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) -{ - struct reiserfs_mount *rmp; - struct reiserfs_sb_info *sbi; - struct reiserfs_super_block *rs; - - reiserfs_log(LOG_DEBUG, "get private data\n"); - rmp = VFSTOREISERFS(mp); - sbi = rmp->rm_reiserfs; - rs = sbi->s_rs; - - reiserfs_log(LOG_DEBUG, "fill statfs structure\n"); - sbp->f_bsize = sbi->s_blocksize; - sbp->f_iosize = sbp->f_bsize; - sbp->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1; - sbp->f_bfree = sb_free_blocks(rs); - sbp->f_bavail = sbp->f_bfree; - sbp->f_files = 0; - sbp->f_ffree = 0; - reiserfs_log(LOG_DEBUG, " block size = %ju\n", - (intmax_t)sbp->f_bsize); - reiserfs_log(LOG_DEBUG, " IO size = %ju\n", - (intmax_t)sbp->f_iosize); - reiserfs_log(LOG_DEBUG, " block count = %ju\n", - (intmax_t)sbp->f_blocks); - reiserfs_log(LOG_DEBUG, " free blocks = %ju\n", - (intmax_t)sbp->f_bfree); - reiserfs_log(LOG_DEBUG, " avail blocks = %ju\n", - (intmax_t)sbp->f_bavail); - reiserfs_log(LOG_DEBUG, "...done\n"); - - if (sbp != &mp->mnt_stat) { - reiserfs_log(LOG_DEBUG, "copying monut point info\n"); - sbp->f_type = mp->mnt_vfc->vfc_typenum; - bcopy((caddr_t)mp->mnt_stat.f_mntonname, - (caddr_t)&sbp->f_mntonname[0], MNAMELEN); - bcopy((caddr_t)mp->mnt_stat.f_mntfromname, - (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); - reiserfs_log(LOG_DEBUG, " mount from: %s\n", - sbp->f_mntfromname); - reiserfs_log(LOG_DEBUG, " mount on: %s\n", - sbp->f_mntonname); - reiserfs_log(LOG_DEBUG, "...done\n"); - } - - return (0); -} - -/* - * File handle to vnode - * - * Have to be really careful about stale file handles: - * - check that the inode key is valid - * - call ffs_vget() to get the locked inode - * - check for an unallocated inode (i_mode == 0) - * - check that the given client host has export rights and return - * those rights via. exflagsp and credanonp - */ -static int -reiserfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) -{ - int error; - struct rfid *rfhp; - struct vnode *nvp; - struct cpu_key key; - struct reiserfs_node *ip; - struct reiserfs_sb_info *sbi; - struct thread *td = curthread; - - rfhp = (struct rfid *)fhp; - sbi = VFSTOREISERFS(mp)->rm_reiserfs; - - /* Check that the key is valid */ - if (rfhp->rfid_dirid < REISERFS_ROOT_PARENT_OBJECTID && - rfhp->rfid_objectid < REISERFS_ROOT_OBJECTID) - return (ESTALE); - - reiserfs_log(LOG_DEBUG, - "file handle key is (dirid=%d, objectid=%d)\n", - rfhp->rfid_dirid, rfhp->rfid_objectid); - key.on_disk_key.k_dir_id = rfhp->rfid_dirid; - key.on_disk_key.k_objectid = rfhp->rfid_objectid; - - reiserfs_log(LOG_DEBUG, "read this inode\n"); - error = reiserfs_iget(mp, &key, &nvp, td); - if (error) { - *vpp = NULLVP; - return (error); - } - - reiserfs_log(LOG_DEBUG, "check validity\n"); - ip = VTOI(nvp); - if (ip->i_mode == 0 || ip->i_generation != rfhp->rfid_gen) { - vput(nvp); - *vpp = NULLVP; - return (ESTALE); - } - - reiserfs_log(LOG_DEBUG, "return it\n"); - *vpp = nvp; - return (0); -} - -/* - * Vnode pointer to File handle - */ -static int -reiserfs_vptofh(struct vnode *vp, struct fid *fhp) -{ - struct rfid *rfhp; - struct reiserfs_node *ip; - - ip = VTOI(vp); - reiserfs_log(LOG_DEBUG, - "fill *fhp with inode (dirid=%d, objectid=%d)\n", - ip->i_ino, ip->i_number); - - rfhp = (struct rfid *)fhp; - rfhp->rfid_len = sizeof(struct rfid); - rfhp->rfid_dirid = ip->i_ino; - rfhp->rfid_objectid = ip->i_number; - rfhp->rfid_gen = ip->i_generation; - - reiserfs_log(LOG_DEBUG, "return it\n"); - return (0); -} - -/* ------------------------------------------------------------------- - * Functions for the journal - * -------------------------------------------------------------------*/ - -int -is_reiserfs_3_5(struct reiserfs_super_block *rs) -{ - - return (!strncmp(rs->s_v1.s_magic, reiserfs_3_5_magic_string, - strlen(reiserfs_3_5_magic_string))); -} - -int -is_reiserfs_3_6(struct reiserfs_super_block *rs) -{ - - return (!strncmp(rs->s_v1.s_magic, reiserfs_3_6_magic_string, - strlen(reiserfs_3_6_magic_string))); -} - -int -is_reiserfs_jr(struct reiserfs_super_block *rs) -{ - - return (!strncmp(rs->s_v1.s_magic, reiserfs_jr_magic_string, - strlen(reiserfs_jr_magic_string))); -} - -static int -is_any_reiserfs_magic_string(struct reiserfs_super_block *rs) -{ - - return ((is_reiserfs_3_5(rs) || is_reiserfs_3_6(rs) || - is_reiserfs_jr(rs))); -} - -/* ------------------------------------------------------------------- - * Internal functions - * -------------------------------------------------------------------*/ - -/* - * Common code for mount and mountroot - */ -static int -reiserfs_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) -{ - int error, old_format = 0; - struct reiserfs_mount *rmp; - struct reiserfs_sb_info *sbi; - struct reiserfs_super_block *rs; - struct cdev *dev = devvp->v_rdev; - -#if (__FreeBSD_version >= 600000) - struct g_consumer *cp; - struct bufobj *bo; -#endif - - //ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - -#if (__FreeBSD_version < 600000) - /* - * Disallow multiple mounts of the same device. - * Disallow mounting of a device that is currently in use - * (except for root, which might share swap device for miniroot). - * Flush out any old buffers remaining from a previous use. - */ - if ((error = vfs_mountedon(devvp)) != 0) - return (error); - if (vcount(devvp) > 1) - return (EBUSY); - - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); - error = vinvalbuf(devvp, V_SAVE, td->td_ucred, td, 0, 0); - if (error) { - VOP_UNLOCK(devvp, 0, td); - return (error); - } - - /* - * Open the device in read-only, 'cause we don't support write - * for now - */ - error = VOP_OPEN(devvp, FREAD, FSCRED, td, -1); - VOP_UNLOCK(devvp, 0, td); - if (error) - return (error); -#else - DROP_GIANT(); - g_topology_lock(); - error = g_vfs_open(devvp, &cp, "reiserfs", /* read-only */ 0); - g_topology_unlock(); - PICKUP_GIANT(); - VOP_UNLOCK(devvp, 0, td); - if (error) - return (error); - - bo = &devvp->v_bufobj; - bo->bo_private = cp; - bo->bo_ops = g_vfs_bufops; -#endif - - if (devvp->v_rdev->si_iosize_max != 0) - mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; - if (mp->mnt_iosize_max > MAXPHYS) - mp->mnt_iosize_max = MAXPHYS; - - rmp = NULL; - sbi = NULL; - - /* rmp contains any information about this specific mount */ - rmp = malloc(sizeof *rmp, M_REISERFSMNT, M_WAITOK | M_ZERO); - if (!rmp) { - error = (ENOMEM); - goto out; - } - sbi = malloc(sizeof *sbi, M_REISERFSMNT, M_WAITOK | M_ZERO); - if (!sbi) { - error = (ENOMEM); - goto out; - } - rmp->rm_reiserfs = sbi; - rmp->rm_mountp = mp; - rmp->rm_devvp = devvp; - rmp->rm_dev = dev; -#if (__FreeBSD_version >= 600000) - rmp->rm_bo = &devvp->v_bufobj; - rmp->rm_cp = cp; -#endif - - /* Set default values for options: non-aggressive tails */ - REISERFS_SB(sbi)->s_mount_opt = (1 << REISERFS_SMALLTAIL); - REISERFS_SB(sbi)->s_rd_only = 1; - REISERFS_SB(sbi)->s_devvp = devvp; - - /* Read the super block */ - if ((error = read_super_block(rmp, REISERFS_OLD_DISK_OFFSET)) == 0) { - /* The read process succeeded, it's an old format */ - old_format = 1; - } else if ((error = read_super_block(rmp, REISERFS_DISK_OFFSET)) != 0) { - reiserfs_log(LOG_ERR, "can not find a ReiserFS filesystem\n"); - goto out; - } - - rs = SB_DISK_SUPER_BLOCK(sbi); - - /* - * Let's do basic sanity check to verify that underlying device is - * not smaller than the filesystem. If the check fails then abort and - * scream, because bad stuff will happen otherwise. - */ -#if 0 - if (s->s_bdev && s->s_bdev->bd_inode && - i_size_read(s->s_bdev->bd_inode) < - sb_block_count(rs) * sb_blocksize(rs)) { - reiserfs_log(LOG_ERR, - "reiserfs: filesystem cannot be mounted because it is " - "bigger than the device.\n"); - reiserfs_log(LOG_ERR, "reiserfs: you may need to run fsck " - "rr may be you forgot to reboot after fdisk when it " - "told you to.\n"); - goto out; - } -#endif - - /* - * XXX This is from the original Linux code, but why affecting 2 values - * to the same variable? - */ - sbi->s_mount_state = SB_REISERFS_STATE(sbi); - sbi->s_mount_state = REISERFS_VALID_FS; - - if ((error = (old_format ? - read_old_bitmaps(rmp) : read_bitmaps(rmp)))) { - reiserfs_log(LOG_ERR, "unable to read bitmap\n"); - goto out; - } - - /* Make data=ordered the default */ - if (!reiserfs_data_log(sbi) && !reiserfs_data_ordered(sbi) && - !reiserfs_data_writeback(sbi)) { - REISERFS_SB(sbi)->s_mount_opt |= (1 << REISERFS_DATA_ORDERED); - } - - if (reiserfs_data_log(sbi)) { - reiserfs_log(LOG_INFO, "using journaled data mode\n"); - } else if (reiserfs_data_ordered(sbi)) { - reiserfs_log(LOG_INFO, "using ordered data mode\n"); - } else { - reiserfs_log(LOG_INFO, "using writeback data mode\n"); - } - - /* TODO Not yet supported */ -#if 0 - if(journal_init(sbi, jdev_name, old_format, commit_max_age)) { - reiserfs_log(LOG_ERR, "unable to initialize journal space\n"); - goto out; - } else { - jinit_done = 1 ; /* once this is set, journal_release must - be called if we error out of the mount */ - } - - if (reread_meta_blocks(sbi)) { - reiserfs_log(LOG_ERR, - "unable to reread meta blocks after journal init\n"); - goto out; - } -#endif - - /* Define and initialize hash function */ - sbi->s_hash_function = hash_function(rmp); - - if (sbi->s_hash_function == NULL) { - reiserfs_log(LOG_ERR, "couldn't determined hash function\n"); - error = (EINVAL); - goto out; - } - - if (is_reiserfs_3_5(rs) || - (is_reiserfs_jr(rs) && SB_VERSION(sbi) == REISERFS_VERSION_1)) - bit_set(&(sbi->s_properties), REISERFS_3_5); - else - bit_set(&(sbi->s_properties), REISERFS_3_6); - - mp->mnt_data = (qaddr_t)rmp; - mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); - mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; - mp->mnt_flag |= MNT_LOCAL; -#if defined(si_mountpoint) - devvp->v_rdev->si_mountpoint = mp; -#endif - - return (0); - -out: - reiserfs_log(LOG_INFO, "*** error during mount ***\n"); - if (sbi) { - if (SB_AP_BITMAP(sbi)) { - int i; - for (i = 0; i < SB_BMAP_NR(sbi); i++) { - if (!SB_AP_BITMAP(sbi)[i].bp_data) - break; - free(SB_AP_BITMAP(sbi)[i].bp_data, M_REISERFSMNT); - } - free(SB_AP_BITMAP(sbi), M_REISERFSMNT); - } - - if (sbi->s_rs) { - free(sbi->s_rs, M_REISERFSMNT); - sbi->s_rs = NULL; - } - } - -#if (__FreeBSD_version < 600000) - (void)VOP_CLOSE(devvp, FREAD, NOCRED, td); -#else - if (cp != NULL) { - DROP_GIANT(); - g_topology_lock(); - g_wither_geom_close(cp->geom, ENXIO); - g_topology_unlock(); - PICKUP_GIANT(); - } -#endif - - if (sbi) - free(sbi, M_REISERFSMNT); - if (rmp) - free(rmp, M_REISERFSMNT); - return (error); -} - -/* - * Read the super block - */ -static int -read_super_block(struct reiserfs_mount *rmp, int offset) -{ - struct buf *bp; - int error, bits; - struct reiserfs_super_block *rs; - struct reiserfs_sb_info *sbi; - uint16_t fs_blocksize; - - if (offset == REISERFS_OLD_DISK_OFFSET) { - reiserfs_log(LOG_DEBUG, - "reiserfs/super: read old format super block\n"); - } else { - reiserfs_log(LOG_DEBUG, - "reiserfs/super: read new format super block\n"); - } - - /* Read the super block */ - if ((error = bread(rmp->rm_devvp, offset * btodb(REISERFS_BSIZE), - REISERFS_BSIZE, NOCRED, &bp)) != 0) { - reiserfs_log(LOG_ERR, "can't read device\n"); - return (error); - } - - /* Get it from the buffer data */ - rs = (struct reiserfs_super_block *)bp->b_data; - if (!is_any_reiserfs_magic_string(rs)) { - brelse(bp); - return (EINVAL); - } - - fs_blocksize = sb_blocksize(rs); - brelse(bp); - bp = NULL; - - if (fs_blocksize <= 0) { - reiserfs_log(LOG_ERR, "unexpected null block size"); - return (EINVAL); - } - - /* Read the super block (for double check) - * We can't read the same blkno with a different size: it causes - * panic() if INVARIANTS is set. So we keep REISERFS_BSIZE */ - if ((error = bread(rmp->rm_devvp, - offset * REISERFS_BSIZE / fs_blocksize * btodb(fs_blocksize), - REISERFS_BSIZE, NOCRED, &bp)) != 0) { - reiserfs_log(LOG_ERR, "can't reread the super block\n"); - return (error); - } - - rs = (struct reiserfs_super_block *)bp->b_data; - if (sb_blocksize(rs) != fs_blocksize) { - reiserfs_log(LOG_ERR, "unexpected block size " - "(found=%u, expected=%u)\n", - sb_blocksize(rs), fs_blocksize); - brelse(bp); - return (EINVAL); - } - - reiserfs_log(LOG_DEBUG, "magic: `%s'\n", rs->s_v1.s_magic); - reiserfs_log(LOG_DEBUG, "label: `%s'\n", rs->s_label); - reiserfs_log(LOG_DEBUG, "block size: %6d\n", sb_blocksize(rs)); - reiserfs_log(LOG_DEBUG, "block count: %6u\n", - rs->s_v1.s_block_count); - reiserfs_log(LOG_DEBUG, "bitmaps number: %6u\n", - rs->s_v1.s_bmap_nr); - - if (rs->s_v1.s_root_block == -1) { - log(LOG_ERR, - "reiserfs: Unfinished reiserfsck --rebuild-tree run " - "detected. Please\n" - "run reiserfsck --rebuild-tree and wait for a " - "completion. If that\n" - "fails, get newer reiserfsprogs package"); - brelse(bp); - return (EINVAL); - } - - sbi = rmp->rm_reiserfs; - sbi->s_blocksize = fs_blocksize; - - for (bits = 9, fs_blocksize >>= 9; fs_blocksize >>= 1; bits++) - ; - sbi->s_blocksize_bits = bits; - - /* Copy the buffer and release it */ - sbi->s_rs = malloc(sizeof *rs, M_REISERFSMNT, M_WAITOK | M_ZERO); - if (!sbi->s_rs) { - reiserfs_log(LOG_ERR, "can not read the super block\n"); - brelse(bp); - return (ENOMEM); - } - bcopy(rs, sbi->s_rs, sizeof(struct reiserfs_super_block)); - brelse(bp); - - if (is_reiserfs_jr(rs)) { - if (sb_version(rs) == REISERFS_VERSION_2) - reiserfs_log(LOG_INFO, "found reiserfs format \"3.6\"" - " with non-standard journal"); - else if (sb_version(rs) == REISERFS_VERSION_1) - reiserfs_log(LOG_INFO, "found reiserfs format \"3.5\"" - " with non-standard journal"); - else { - reiserfs_log(LOG_ERR, "found unknown " - "format \"%u\" of reiserfs with non-standard magic", - sb_version(rs)); - return (EINVAL); - } - } else { - /* - * s_version of standard format may contain incorrect - * information, so we just look at the magic string - */ - reiserfs_log(LOG_INFO, - "found reiserfs format \"%s\" with standard journal\n", - is_reiserfs_3_5(rs) ? "3.5" : "3.6"); - } - - return (0); -} - -/* - * load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure - * from disk. - * @sbi - superblock info for this filesystem - * @bi - the bitmap info to be loaded. Requires that bi->bp is valid. - * - * This routine counts how many free bits there are, finding the first - * zero as a side effect. Could also be implemented as a loop of - * test_bit() calls, or a loop of find_first_zero_bit() calls. This - * implementation is similar to find_first_zero_bit(), but doesn't - * return after it finds the first bit. Should only be called on fs - * mount, but should be fairly efficient anyways. - * - * bi->first_zero_hint is considered unset if it == 0, since the bitmap - * itself will invariably occupt block 0 represented in the bitmap. The - * only exception to this is when free_count also == 0, since there will - * be no free blocks at all. - */ -static void -load_bitmap_info_data(struct reiserfs_sb_info *sbi, - struct reiserfs_bitmap_info *bi) -{ - unsigned long *cur; - - cur = (unsigned long *)bi->bp_data; - while ((char *)cur < (bi->bp_data + sbi->s_blocksize)) { - /* - * No need to scan if all 0's or all 1's. - * Since we're only counting 0's, we can simply ignore - * all 1's - */ - if (*cur == 0) { - if (bi->first_zero_hint == 0) { - bi->first_zero_hint = - ((char *)cur - bi->bp_data) << 3; - } - bi->free_count += sizeof(unsigned long) * 8; - } else if (*cur != ~0L) { - int b; - - for (b = 0; b < sizeof(unsigned long) * 8; b++) { - if (!reiserfs_test_le_bit(b, cur)) { - bi->free_count++; - if (bi->first_zero_hint == 0) - bi->first_zero_hint = - (((char *)cur - - bi->bp_data) << 3) + b; - } - } - } - cur++; - } -} - -/* - * Read the bitmaps - */ -static int -read_bitmaps(struct reiserfs_mount *rmp) -{ - int i, bmap_nr; - struct buf *bp = NULL; - struct reiserfs_sb_info *sbi = rmp->rm_reiserfs; - - /* Allocate memory for the table of bitmaps */ - SB_AP_BITMAP(sbi) = - malloc(sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(sbi), - M_REISERFSMNT, M_WAITOK | M_ZERO); - if (!SB_AP_BITMAP(sbi)) - return (ENOMEM); - - /* Read all the bitmaps */ - for (i = 0, - bmap_nr = (REISERFS_DISK_OFFSET_IN_BYTES / sbi->s_blocksize + 1) * - btodb(sbi->s_blocksize); - i < SB_BMAP_NR(sbi); i++, bmap_nr = sbi->s_blocksize * 8 * i) { - SB_AP_BITMAP(sbi)[i].bp_data = malloc(sbi->s_blocksize, - M_REISERFSMNT, M_WAITOK | M_ZERO); - if (!SB_AP_BITMAP(sbi)[i].bp_data) - return (ENOMEM); - bread(rmp->rm_devvp, bmap_nr, sbi->s_blocksize, NOCRED, &bp); - bcopy(bp->b_data, SB_AP_BITMAP(sbi)[i].bp_data, - sbi->s_blocksize); - brelse(bp); - bp = NULL; - - /*if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) - ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh);*/ - } - - for (i = 0; i < SB_BMAP_NR(sbi); i++) { - /*if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) { - reiserfs_warning(s,"sh-2029: reiserfs read_bitmaps: " - "bitmap block (#%lu) reading failed", - SB_AP_BITMAP(s)[i].bh->b_blocknr); - for (i = 0; i < SB_BMAP_NR(s); i++) - brelse(SB_AP_BITMAP(s)[i].bh); - vfree(SB_AP_BITMAP(s)); - SB_AP_BITMAP(s) = NULL; - return 1; - }*/ - load_bitmap_info_data(sbi, SB_AP_BITMAP(sbi) + i); - reiserfs_log(LOG_DEBUG, - "%d free blocks (starting at block %ld)\n", - SB_AP_BITMAP(sbi)[i].free_count, - (long)SB_AP_BITMAP(sbi)[i].first_zero_hint); - } - - return (0); -} - -// TODO Not supported -static int -read_old_bitmaps(struct reiserfs_mount *rmp) -{ - - return (EOPNOTSUPP); -#if 0 - int i; - struct reiserfs_sb_info *sbi = rmp->rm_reiserfs; - struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(sbi); - - /* First of bitmap blocks */ - int bmp1 = (REISERFS_OLD_DISK_OFFSET / sbi->s_blocksize) * - btodb(sbi->s_blocksize); - - /* Read true bitmap */ - SB_AP_BITMAP(sbi) = - malloc(sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs), - M_REISERFSMNT, M_WAITOK | M_ZERO); - if (!SB_AP_BITMAP(sbi)) - return 1; - - for (i = 0; i < sb_bmap_nr(rs); i ++) { - SB_AP_BITMAP(sbi)[i].bp = getblk(rmp->rm_devvp, - (bmp1 + i) * btodb(sbi->s_blocksize), sbi->s_blocksize, 0, 0, 0); - if (!SB_AP_BITMAP(sbi)[i].bp) - return 1; - load_bitmap_info_data(sbi, SB_AP_BITMAP(sbi) + i); - } - - return 0; -#endif -} - -/* ------------------------------------------------------------------- - * Hash detection stuff - * -------------------------------------------------------------------*/ - -static int -get_root_node(struct reiserfs_mount *rmp, struct reiserfs_node **root) -{ - struct reiserfs_node *ip; - struct reiserfs_iget_args args; - - /* Allocate the node structure */ - reiserfs_log(LOG_DEBUG, "malloc(struct reiserfs_node)\n"); - MALLOC(ip, struct reiserfs_node *, sizeof(struct reiserfs_node), - M_REISERFSNODE, M_WAITOK | M_ZERO); - - /* Fill the structure */ - reiserfs_log(LOG_DEBUG, "filling *ip\n"); - ip->i_dev = rmp->rm_dev; - ip->i_number = REISERFS_ROOT_OBJECTID; - ip->i_ino = REISERFS_ROOT_PARENT_OBJECTID; - ip->i_reiserfs = rmp->rm_reiserfs; - - /* Read the inode */ - args.objectid = ip->i_number; - args.dirid = ip->i_ino; - reiserfs_log(LOG_DEBUG, "call reiserfs_read_locked_inode(" - "objectid=%d,dirid=%d)\n", args.objectid, args.dirid); - reiserfs_read_locked_inode(ip, &args); - - ip->i_devvp = rmp->rm_devvp; - //XXX VREF(ip->i_devvp); Is it necessary ? - - *root = ip; - return (0); -} - -/* - * If root directory is empty - we set default - Yura's - hash and warn - * about it. - * FIXME: we look for only one name in a directory. If tea and yura both - * have the same value - we ask user to send report to the mailing list - */ -uint32_t find_hash_out(struct reiserfs_mount *rmp) -{ - int retval; - struct cpu_key key; - INITIALIZE_PATH(path); - struct reiserfs_node *ip; - struct reiserfs_sb_info *sbi; - struct reiserfs_dir_entry de; - uint32_t hash = DEFAULT_HASH; - - get_root_node(rmp, &ip); - if (!ip) - return (UNSET_HASH); - - sbi = rmp->rm_reiserfs; - - do { - uint32_t teahash, r5hash, yurahash; - - reiserfs_log(LOG_DEBUG, "make_cpu_key\n"); - make_cpu_key(&key, ip, ~0, TYPE_DIRENTRY, 3); - reiserfs_log(LOG_DEBUG, "search_by_entry_key for " - "key(objectid=%d,dirid=%d)\n", - key.on_disk_key.k_objectid, key.on_disk_key.k_dir_id); - retval = search_by_entry_key(sbi, &key, &path, &de); - if (retval == IO_ERROR) { - pathrelse(&path); - return (UNSET_HASH); - } - if (retval == NAME_NOT_FOUND) - de.de_entry_num--; - - reiserfs_log(LOG_DEBUG, "name found\n"); - - set_de_name_and_namelen(&de); - - if (deh_offset(&(de.de_deh[de.de_entry_num])) == DOT_DOT_OFFSET) { - /* Allow override in this case */ - if (reiserfs_rupasov_hash(sbi)) { - hash = YURA_HASH; - } - reiserfs_log(LOG_DEBUG, - "FS seems to be empty, autodetect " - "is using the default hash"); - break; - } - - r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen)); - teahash = GET_HASH_VALUE(keyed_hash(de.de_name, - de.de_namelen)); - yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen)); - if (((teahash == r5hash) && - (GET_HASH_VALUE( - deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash)) || - ((teahash == yurahash) && - (yurahash == - GET_HASH_VALUE( - deh_offset(&(de.de_deh[de.de_entry_num]))))) || - ((r5hash == yurahash) && - (yurahash == - GET_HASH_VALUE( - deh_offset(&(de.de_deh[de.de_entry_num])))))) { - reiserfs_log(LOG_ERR, - "unable to automatically detect hash " - "function. Please mount with -o " - "hash={tea,rupasov,r5}"); - hash = UNSET_HASH; - break; - } - - if (GET_HASH_VALUE( - deh_offset(&(de.de_deh[de.de_entry_num]))) == yurahash) { - reiserfs_log(LOG_DEBUG, "detected YURA hash\n"); - hash = YURA_HASH; - } else if (GET_HASH_VALUE( - deh_offset(&(de.de_deh[de.de_entry_num]))) == teahash) { - reiserfs_log(LOG_DEBUG, "detected TEA hash\n"); - hash = TEA_HASH; - } else if (GET_HASH_VALUE( - deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) { - reiserfs_log(LOG_DEBUG, "detected R5 hash\n"); - hash = R5_HASH; - } else { - reiserfs_log(LOG_WARNING, "unrecognised hash function"); - hash = UNSET_HASH; - } - } while (0); - - pathrelse(&path); - return (hash); -} - -/* Finds out which hash names are sorted with */ -static int -what_hash(struct reiserfs_mount *rmp) -{ - uint32_t code; - struct reiserfs_sb_info *sbi = rmp->rm_reiserfs; - - find_hash_out(rmp); - code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(sbi)); - - /* - * reiserfs_hash_detect() == true if any of the hash mount options - * were used. We must check them to make sure the user isn't using a - * bad hash value - */ - if (code == UNSET_HASH || reiserfs_hash_detect(sbi)) - code = find_hash_out(rmp); - - if (code != UNSET_HASH && reiserfs_hash_detect(sbi)) { - /* - * Detection has found the hash, and we must check against - * the mount options - */ - if (reiserfs_rupasov_hash(sbi) && code != YURA_HASH) { - reiserfs_log(LOG_ERR, "error, %s hash detected, " - "unable to force rupasov hash", - reiserfs_hashname(code)); - code = UNSET_HASH; - } else if (reiserfs_tea_hash(sbi) && code != TEA_HASH) { - reiserfs_log(LOG_ERR, "error, %s hash detected, " - "unable to force tea hash", - reiserfs_hashname(code)); - code = UNSET_HASH; - } else if (reiserfs_r5_hash(sbi) && code != R5_HASH) { - reiserfs_log(LOG_ERR, "error, %s hash detected, " - "unable to force r5 hash", - reiserfs_hashname(code)); - code = UNSET_HASH; - } - } else { - /* - * Find_hash_out was not called or could not determine - * the hash - */ - if (reiserfs_rupasov_hash(sbi)) { - code = YURA_HASH; - } else if (reiserfs_tea_hash(sbi)) { - code = TEA_HASH; - } else if (reiserfs_r5_hash(sbi)) { - code = R5_HASH; - } - } - - /* TODO Not supported yet */ -#if 0 - /* If we are mounted RW, and we have a new valid hash code, update - * the super */ - if (code != UNSET_HASH && - !(s->s_flags & MS_RDONLY) && - code != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) { - set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code); - } -#endif - - return (code); -} - -/* Return pointer to appropriate function */ -static hashf_t -hash_function(struct reiserfs_mount *rmp) -{ - - switch (what_hash(rmp)) { - case TEA_HASH: - reiserfs_log(LOG_INFO, "using tea hash to sort names\n"); - return (keyed_hash); - case YURA_HASH: - reiserfs_log(LOG_INFO, "using rupasov hash to sort names\n"); - return (yura_hash); - case R5_HASH: - reiserfs_log(LOG_INFO, "using r5 hash to sort names\n"); - return (r5_hash); - } - - return (NULL); -} - -/* ------------------------------------------------------------------- - * VFS registration - * -------------------------------------------------------------------*/ - -static struct vfsops reiser_vfsops = { - .vfs_cmount = reiserfs_cmount, - .vfs_mount = reiserfs_mount, - .vfs_unmount = reiserfs_unmount, - //.vfs_checkexp = reiserfs_checkexp, - //.vfs_extattrctl = reiserfs_extattrctl, - .vfs_fhtovp = reiserfs_fhtovp, - //.vfs_quotactl = reiserfs_quotactl, - .vfs_root = reiserfs_root, - //.vfs_start = reiserfs_start, - .vfs_statfs = reiserfs_statfs, - //.vfs_sync = reiserfs_sync, - //.vfs_vget = reiserfs_vget, - .vfs_vptofh = reiserfs_vptofh, -}; - -VFS_SET(reiser_vfsops, reiserfs, VFCF_READONLY); |