#ident "$Revision: 1.20 $" #include #include #include #define _KERNEL 1 #include #include #include #include #include #include #include #include #undef _KERNEL #include #include #include #include #include #include #include #include #include #include #include #include #include "xfs_types.h" #include "xfs_inum.h" #include "xfs_sb.h" #include "xfs_ag.h" #include "xfs_log.h" #include "xfs_trans.h" #include "xfs_mount.h" #include "xfs_alloc_btree.h" #include "xfs_bmap_btree.h" #include "xfs_ialloc_btree.h" #include "xfs_btree.h" #include "xfs_bmap.h" #include "xfs_ialloc.h" #include "xfs_dinode.h" #include "xfs_inode_item.h" #include "xfs_inode.h" #include "sim.h" vnode_t *root_vp, *vp1, *vp2, *vp6, *tvp, *dir1_vp, *dir2_vp; vnode_t *vp_symlink, *dir22_vp; int root_vp_c, vp1_c, vp2_c, vp6_c, dir1_vp_c, dir2_vp_c; int vp_symlink_c, dir22_vp_c; static void check_vlinks(void) { /* * Check the vnode ref counts. */ if (root_vp) ASSERT (root_vp->v_count == root_vp_c); if (vp1) ASSERT (vp1->v_count == vp1_c); if (vp2) ASSERT (vp2->v_count == vp2_c); if (vp6) ASSERT (vp6->v_count == vp6_c); if (dir1_vp) ASSERT (dir1_vp->v_count == dir1_vp_c); if (dir2_vp) ASSERT (dir2_vp->v_count == dir2_vp_c); if (vp_symlink) ASSERT (vp_symlink->v_count == vp_symlink_c); } main(int argc, char **argv) { xfs_mount_t *mp; xfs_sb_t *sbp; xfs_inode_t *ip; xfs_inode_t *ip2; xfs_inode_t *ip3; xfs_trans_t *tp; struct cred cred; xfs_ino_t ino; int x, i; vattr_t vap; sim_init_t si; boolean_t call_again; buf_t *ag_buf; pathname_t pn; int error; int eof; uio_t uio; iovec_t vec; struct dirent *dir_entry; char symlink[1024]; int bytes_left; char *byte_p; char *long_path; char *long_path2; char *log; int fflag; int c; if (argc < 2) { printf("usage: vdir [-f] [-l logdev] \n"); exit(1); } xlog_debug = 0; fflag = 0; log = NULL; while ((c = getopt(argc, argv, "fl:")) != EOF) { switch (c) { case 'f': fflag = 1; break; case 'l': log = optarg; xlog_debug = 1; break; case '?': printf("usage: vdir [-f] [-l logdev] \n"); exit(1); } } if (argc - optind != 1) { printf("usage: vdir [-f] [-l logdev] \n"); exit(1); } bzero(&si, sizeof(si)); si.dname = argv[optind]; si.disfile = fflag; si.logname = log; si.lisfile = fflag; printf("mount %s\n", si.dname); xfs_sim_init(&si); mp = xfs_mount(si.ddev, si.logdev, si.rtdev); sbp = &mp->m_sb; if (sbp->sb_magicnum != XFS_SB_MAGIC) { fprintf(stderr, "%s: magic number %d is wrong\n", si.dname, sbp->sb_magicnum); exit(1); } /* * Get the root inode. */ ino = sbp->sb_rootino; tp = xfs_trans_alloc(mp, 7); if (xfs_trans_reserve(tp, 32, BBTOB(128), 0, 0) != 0) { xfs_trans_cancel(tp, 0); printf("Out of space\n"); bflush(si.ddev); exit(1); } ip = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); root_vp = XFS_ITOV(ip); VN_HOLD(root_vp); root_vp_c = 1; /* track vp->v_count */ xfs_trans_commit (tp, 0); /* Run as root. */ cred.cr_uid = 0; /* * VOP_LOOKUP - failure case. */ pn_alloc (&pn); pn_set (&pn, "file1"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_LOOKUP(root_vp, "file1", &tvp, &pn, 0, root_vp, &cred); ASSERT (error == ENOENT); check_vlinks(); /* * VOP_CREATE - success case. */ vap.va_type = VREG; vap.va_mode = 0777; error = VOP_CREATE(root_vp, "file1", &vap, 0, 0777, &vp1, &cred); ASSERT (! error); vp1_c = 1; check_vlinks(); /* * VOP_CREATE - success case. */ error = VOP_CREATE(root_vp, "file2", &vap, 0, 0777, &vp2, &cred); ASSERT ((! error) && (vp2 != vp1)); vp2_c = 1; check_vlinks(); #if 0 /* * VOP_CREATE - truncate case. Not implemented. */ error = VOP_CREATE(root_vp, "file2", &vap, 0, 0777, &vp2, &cred); ASSERT (error == EEXIST); #endif /* * VOP_LOOKUP - success case. */ error = VOP_LOOKUP(root_vp, "file1", &tvp, &pn, 0, root_vp, &cred); ASSERT ((! error) && (tvp == vp1)); vp1_c ++; check_vlinks(); /* * VOP_REMOVE - success case. */ error = VOP_REMOVE(root_vp, "file1", &cred); ASSERT (! error); check_vlinks(); /* * VOP_REMOVE - failure cases. */ error = VOP_REMOVE(root_vp, "file1", &cred); ASSERT (error == ENOENT); check_vlinks(); error = VOP_REMOVE(root_vp, "..", &cred); ASSERT (error == EEXIST); check_vlinks(); /* * VOP_LINK - success case. */ error = VOP_LINK(root_vp, vp2, "link1", &cred); ASSERT (! error); check_vlinks(); /* * VOP_LINK -failure case. */ error = VOP_LINK(root_vp, vp2, "file2", &cred); ASSERT (error == EEXIST); check_vlinks(); /* * Now do a lookup using the link. */ pn_set (&pn, "link1"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_LOOKUP(root_vp, "link1", &tvp, &pn, 0, root_vp, &cred); ASSERT ((!error) && (tvp == vp2)); vp2_c++; /* link1 is linked to vp2 */ check_vlinks(); /* * Now create a directory. */ vap.va_type = VDIR; error = VOP_MKDIR(root_vp, "dir1", &vap, &dir1_vp, &cred); ASSERT (!error); dir1_vp_c ++; check_vlinks(); VN_RELE (vp1); vp1_c--; check_vlinks(); /* * MKDIR - failure case. */ vap.va_type = VDIR; error = VOP_MKDIR(root_vp, "dir1", &vap, &dir1_vp, &cred); ASSERT (error == EEXIST); check_vlinks(); /* * Add entry to directory */ vap.va_type = VREG; vap.va_mode = 0777; error = VOP_CREATE(dir1_vp, "file1", &vap, 0, 0777, &tvp, &cred); ASSERT (!error); VN_RELE (tvp); ASSERT (tvp->v_count == 0); check_vlinks(); /* * Get directory entries. success case. */ vec.iov_len = 4096; dir_entry = (struct dirent *) malloc (4096); vec.iov_base = (caddr_t) dir_entry; uio.uio_iov = &vec; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_segflg = UIO_SYSSPACE; uio.uio_resid = vec.iov_len; error = VOP_READDIR (dir1_vp, &uio, &cred, &eof); ASSERT (! error); ASSERT (eof); /* * We know that there are 3 entries. ".", "..", and "file1". */ bytes_left = 4096 - uio.uio_resid; while (bytes_left) { printf ("[%s (%d)] ", dir_entry->d_name, dir_entry->d_ino); byte_p = (unsigned char *) dir_entry + dir_entry->d_reclen; bytes_left -= dir_entry->d_reclen; dir_entry = (struct dirent *) byte_p; } printf ("\n"); /* * Remove directory. Fail - not empty. */ error = VOP_RMDIR(root_vp, "dir1", root_vp, &cred); ASSERT (error == EEXIST); check_vlinks(); /* * VOP_SYMLINK - success case (inline). * * create a link to /dir1/file1 from /symlink_1. */ vap.va_type = VLNK; vap.va_mode = 0777; error = VOP_SYMLINK(root_vp, "symlink_1", &vap, "/dir1/file1", &cred); ASSERT (!error); /* * VOP_SYMLINK - failure case. */ error = VOP_SYMLINK(root_vp, "symlink_1", &vap, "/dir1/fileXY", &cred); ASSERT (error == EEXIST); /* * VOP_SYMLINK - very long symlink. * aaa...aaaa/aaaaa...aaaa/aaaaa...aaaa/.... etc. */ #define MAX_P_LEN 1023 long_path = (char *)malloc (MAX_P_LEN); memset (long_path, 'a', MAX_P_LEN); for (i=100; iv_type == VLNK); vp_symlink_c = 1; check_vlinks(); long_path2 = (char *)malloc(MAX_P_LEN); bzero (long_path2, MAX_P_LEN); vec.iov_len = MAX_P_LEN; vec.iov_base = (caddr_t) long_path2; uio.uio_iov = &vec; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_segflg = UIO_SYSSPACE; uio.uio_resid = vec.iov_len; error = VOP_READLINK (vp_symlink, &uio, &cred); ASSERT (! error); ASSERT (strncmp (long_path2, long_path, MAX_P_LEN) == 0); check_vlinks(); /* * VOP_READLINK - success case (inline). */ pn_set (&pn, "symlink_1"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_LOOKUP(root_vp, "symlink_1", &vp_symlink, &pn, 0, root_vp, &cred); ASSERT (!error); ASSERT (vp_symlink->v_type == VLNK); vp_symlink_c = 1; check_vlinks(); vec.iov_len = 1024; vec.iov_base = (caddr_t) symlink; uio.uio_iov = &vec; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_segflg = UIO_SYSSPACE; uio.uio_resid = vec.iov_len; error = VOP_READLINK (vp_symlink, &uio, &cred); ASSERT (! error); ASSERT (strncmp (symlink, "/dir1/file1", strlen("/dir1/file1")) == 0); check_vlinks(); /* * VOP_READLINK - failure case (inline). */ uio.uio_iov = &vec; uio.uio_iovcnt = 1; uio.uio_offset = -1; /* invalid */ uio.uio_resid = vec.iov_len; error = VOP_READLINK (vp_symlink, &uio, &cred); ASSERT (error == EINVAL); check_vlinks(); /* * Rename /dir1/file1 to /file3.. */ pn_set (&pn, "file3"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_RENAME(dir1_vp, "file1", root_vp, "file3", &pn, &cred); ASSERT (!error); check_vlinks(); /* * Rename /file3 to /file4. */ pn_set (&pn, "file4"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_RENAME(root_vp, "file3", root_vp, "file4", &pn, &cred); ASSERT (!error); check_vlinks(); /* * Verify that lookup of /file3 fails. */ pn_set (&pn, "file3"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_LOOKUP(root_vp, "file3", &tvp, &pn, 0, root_vp, &cred); ASSERT (error == ENOENT); check_vlinks(); /* * Rename /file4 to /file4. */ pn_set (&pn, "file4"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_RENAME(root_vp, "file4", root_vp, "file4", &pn, &cred); ASSERT (!error); check_vlinks(); /* * Rename /file_not to /file4. (failure case) */ error = VOP_RENAME(root_vp, "file_not", root_vp, "file4", &pn, &cred); ASSERT (error == ENOENT); check_vlinks(); /* * Rename /file4 to /file2 (exists) */ pn_set (&pn, "file2"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_RENAME(root_vp, "file4", root_vp, "file2", &pn, &cred); ASSERT (!error); check_vlinks(); /* * Rename a directory to a file. (failure case.) */ pn_set (&pn, "file2"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_RENAME(root_vp, "dir1", root_vp, "file2", &pn, &cred); ASSERT (error == ENOTDIR); check_vlinks(); /* * Rename a directory. /dir1 to /dir2. */ pn_set (&pn, "dir2"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_RENAME(root_vp, "dir1", root_vp, "dir2", &pn, &cred); ASSERT (!error); check_vlinks(); /* * Add entry to the newly renamed directory */ error = VOP_LOOKUP(root_vp, "dir2", &dir2_vp, &pn, 0, root_vp, &cred); ASSERT ((! error) && (dir2_vp == dir1_vp)); /* dir1_vp & dir2_vp now point to the same vnode. So update both counts */ dir1_vp_c++; dir2_vp_c = dir1_vp_c; check_vlinks(); vap.va_type = VREG; vap.va_mode = 0777; error = VOP_CREATE(dir2_vp, "file6", &vap, 0, 0777, &vp6, &cred); vp6_c = 1; ASSERT (!error); check_vlinks(); /* * Create directory /dir2/dir22. */ vap.va_type = VDIR; error = VOP_MKDIR(dir2_vp, "dir22", &vap, &dir22_vp, &cred); ASSERT (!error); dir22_vp_c = 1; check_vlinks(); /* * Rename a directory under itself - failure case. */ pn_set (&pn, "dir2"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_RENAME(root_vp, "dir2", dir22_vp, "dir2", &pn, &cred); ASSERT (error == EINVAL); check_vlinks(); /* * Rename /dir2/dir22 to /dir3. */ pn_set (&pn, "dir3"); pn.pn_complen = strlen(pn.pn_buf); error = VOP_RENAME(dir2_vp, "dir22", root_vp, "dir3", &pn, &cred); ASSERT (! error); check_vlinks(); /* * Remove directory /dir2 - failure case. */ error = VOP_RMDIR(root_vp, "dir2", root_vp, &cred); ASSERT (error == EEXIST); check_vlinks(); /* * Remove the file /dir2/file6. */ error = VOP_REMOVE(dir2_vp, "file6", &cred); ASSERT (!error); check_vlinks(); /* * Remove directory /dir2. */ error = VOP_RMDIR(root_vp, "dir2", root_vp, &cred); ASSERT (!error); check_vlinks(); /* * Create a directory under a link & then look up the * directory in the original place. */ /* * Release some of the vnodes. */ VN_RELE(root_vp); for (i=0; i