HAMMER 26/many: Misc features.
authorMatthew Dillon <dillon@dragonflybsd.org>
Wed, 6 Feb 2008 08:59:28 +0000 (08:59 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Wed, 6 Feb 2008 08:59:28 +0000 (08:59 +0000)
* Add an inode flag to lock the transaction id used to update the inode
  on-disk.  This is used for both inode creation and rename to synchronize
  the inode with the related directory entry so historical lookups do not
  get confused.

* Add a capability to prune all deleted records.

* Properly set the file size for softlinks to reflect the length of
  the softlink string (fixes a NFS issue).

* Add additional device checks to the mount code to detect block devices
  which are already in use.

* Implement the noatime mount option.

* Implement a poor-man's fakename for NFS when backing out of a historical
  access.

* Properly connect ".." for a renamed directory to the new parent directory.

sys/vfs/hammer/hammer.h
sys/vfs/hammer/hammer_inode.c
sys/vfs/hammer/hammer_ioctl.c
sys/vfs/hammer/hammer_ioctl.h
sys/vfs/hammer/hammer_ondisk.c
sys/vfs/hammer/hammer_vnops.c

index a06ce33..836eeb6 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/hammer/hammer.h,v 1.33 2008/02/05 20:52:01 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer.h,v 1.34 2008/02/06 08:59:28 dillon Exp $
  */
 /*
  * This header file contains structures used internally by the HAMMERFS
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/kernel.h>
+#include <sys/conf.h>
 #include <sys/systm.h>
 #include <sys/tree.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
 #include <sys/mountctl.h>
 #include <sys/vnode.h>
+#include <sys/proc.h>
 #include <sys/globaldata.h>
 #include <sys/lockf.h>
 #include <sys/buf.h>
@@ -188,6 +190,7 @@ typedef struct hammer_inode *hammer_inode_t;
 #define HAMMER_INODE_GONE      0x0400  /* delete flushed out */
 #define HAMMER_INODE_DONDISK   0x0800  /* data records may be on disk */
 #define HAMMER_INODE_BUFS      0x1000  /* dirty high level bps present */
+#define HAMMER_INODE_TIDLOCKED 0x2000  /* tid locked until inode synced */
 
 #define HAMMER_INODE_MODMASK   (HAMMER_INODE_DDIRTY|HAMMER_INODE_RDIRTY| \
                                 HAMMER_INODE_XDIRTY|HAMMER_INODE_BUFS|   \
index e92da9d..154fc96 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/hammer/hammer_inode.c,v 1.27 2008/02/05 20:52:01 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_inode.c,v 1.28 2008/02/06 08:59:28 dillon Exp $
  */
 
 #include "hammer.h"
@@ -133,8 +133,17 @@ hammer_get_vnode(struct hammer_inode *ip, int lktype, struct vnode **vpp)
                        default:
                                break;
                        }
-                       if (ip->obj_id == HAMMER_OBJID_ROOT)
+
+                       /*
+                        * Only mark as the root vnode if the ip is not
+                        * historical, otherwise the VFS cache will get
+                        * confused.  The other half of the special handling
+                        * is in hammer_vop_nlookupdotdot().
+                        */
+                       if (ip->obj_id == HAMMER_OBJID_ROOT &&
+                           ip->obj_asof == ip->hmp->asof) {
                                vp->v_flag |= VROOT;
+                       }
 
                        vp->v_data = (void *)ip;
                        /* vnode locked by getnewvnode() */
@@ -287,7 +296,7 @@ hammer_create_inode(hammer_transaction_t trans, struct vattr *vap,
        ip->obj_asof = hmp->asof;
        ip->hmp = hmp;
        ip->flags = HAMMER_INODE_DDIRTY | HAMMER_INODE_RDIRTY |
-                   HAMMER_INODE_ITIMES;
+                   HAMMER_INODE_ITIMES | HAMMER_INODE_TIDLOCKED;
        ip->last_tid = trans->tid;
 
        RB_INIT(&ip->rec_tree);
@@ -433,6 +442,12 @@ retry:
                                ++ip->hmp->rootvol->ondisk->vol0_stat_inodes;
                                ip->flags |= HAMMER_INODE_ONDISK;
                        }
+
+                       /*
+                        * Unlock the sync TID if it was locked, now that
+                        * we have written it out to disk.
+                        */
+                       ip->flags &= ~HAMMER_INODE_TIDLOCKED;
                }
        }
        return(error);
@@ -558,7 +573,15 @@ hammer_modify_inode(struct hammer_transaction *trans,
                        kprintf("hammer_modify_inode: %016llx (%08x)\n", 
                                trans->tid, (int)(trans->tid / 1000000000LL));
                }
-               if (ip->flags & HAMMER_INODE_ONDISK)
+
+               /*
+                * Update the inode sync transaction id unless it's locked
+                * due to some prior required synchroznization.  Locking the
+                * tid in the new flags overrides this (used by rename).
+                */
+               if ((ip->flags & HAMMER_INODE_TIDLOCKED) == 0)
+                       ip->last_tid = trans->tid;
+               else if (flags & HAMMER_INODE_TIDLOCKED)
                        ip->last_tid = trans->tid;
        }
        ip->flags |= flags;
index 347e685..bcf21a5 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/hammer/hammer_ioctl.c,v 1.2 2008/02/05 07:58:43 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_ioctl.c,v 1.3 2008/02/06 08:59:28 dillon Exp $
  */
 
 #include "hammer.h"
@@ -90,12 +90,12 @@ hammer_ioc_prune(hammer_inode_t ip, struct hammer_ioc_prune *prune)
        int realign_cre;
        int realign_del;
 
-       if (prune->nelms < 0 || prune->nelms > HAMMER_MAX_PRUNE_ELMS) {
+       if (prune->nelms < 0 || prune->nelms > HAMMER_MAX_PRUNE_ELMS)
                return(EINVAL);
-       }
-       if (prune->beg_obj_id >= prune->end_obj_id) {
+       if (prune->beg_obj_id >= prune->end_obj_id)
+               return(EINVAL);
+       if ((prune->flags & HAMMER_IOC_PRUNE_ALL) && prune->nelms)
                return(EINVAL);
-       }
 
 retry:
        error = hammer_init_cursor_hmp(&cursor, NULL, ip->hmp);
@@ -124,6 +124,7 @@ retry:
                elm = &cursor.node->ondisk->elms[cursor.index];
                prune->cur_obj_id = elm->base.obj_id;
                prune->cur_key = elm->base.key;
+
                if (check_prune(prune, elm, &realign_cre, &realign_del) == 0) {
                        if (hammer_debug_general & 0x0200) {
                                kprintf("check %016llx %016llx: DELETE\n",
@@ -187,6 +188,16 @@ check_prune(struct hammer_ioc_prune *prune, hammer_btree_elm_t elm,
        *realign_cre = -1;
        *realign_del = -1;
 
+       /*
+        * If pruning everything remove all records with a non-zero
+        * delete_tid.
+        */
+       if (prune->flags & HAMMER_IOC_PRUNE_ALL) {
+               if (elm->base.delete_tid != 0)
+                       return(0);
+               return(-1);
+       }
+
        for (i = 0; i < prune->nelms; ++i) {
                scan = &prune->elms[i];
 
index 82872b3..56f2212 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/hammer/hammer_ioctl.h,v 1.2 2008/02/05 07:58:43 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_ioctl.h,v 1.3 2008/02/06 08:59:28 dillon Exp $
  */
 /*
  * HAMMER ioctl's.  This file can be #included from userland
@@ -60,7 +60,7 @@ struct hammer_ioc_prune_elm {
 
 struct hammer_ioc_prune {
        int             nelms;
-       int             reserved01;
+       int             flags;
        int64_t         beg_obj_id;
        int64_t         cur_obj_id;     /* initialize to end_obj_id */
        int64_t         cur_key;        /* initialize to HAMMER_MAX_KEY */
@@ -74,6 +74,9 @@ struct hammer_ioc_prune {
        struct hammer_ioc_prune_elm elms[HAMMER_MAX_PRUNE_ELMS];
 };
 
+#define HAMMER_IOC_PRUNE_ALL   0x0001
+
+
 /*
  * HAMMERIOC_GETHISTORY
  *
index 5536eb0..3f62cf0 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/hammer/hammer_ondisk.c,v 1.26 2008/01/25 10:36:04 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_ondisk.c,v 1.27 2008/02/06 08:59:28 dillon Exp $
  */
 /*
  * Manage HAMMER's on-disk structures.  These routines are primarily
@@ -220,18 +220,29 @@ hammer_install_volume(struct hammer_mount *hmp, const char *volname)
                error = cache_vref(&nd.nl_nch, nd.nl_cred, &volume->devvp);
        nlookup_done(&nd);
        if (error == 0) {
-               vn_isdisk(volume->devvp, &error);
+               if (vn_isdisk(volume->devvp, &error)) {
+                       error = vfs_mountedon(volume->devvp);
+               }
+       }
+       if (error == 0 &&
+           count_udev(volume->devvp->v_umajor, volume->devvp->v_uminor) > 0) {
+               error = EBUSY;
        }
        if (error == 0) {
                vn_lock(volume->devvp, LK_EXCLUSIVE | LK_RETRY);
-               error = VOP_OPEN(volume->devvp, (ronly ? FREAD : FREAD|FWRITE),
-                                FSCRED, NULL);
+               error = vinvalbuf(volume->devvp, V_SAVE, 0, 0);
+               if (error == 0) {
+                       error = VOP_OPEN(volume->devvp, 
+                                        (ronly ? FREAD : FREAD|FWRITE),
+                                        FSCRED, NULL);
+               }
                vn_unlock(volume->devvp);
        }
        if (error) {
                hammer_free_volume(volume);
                return(error);
        }
+       volume->devvp->v_rdev->si_mountpoint = mp;
 
        /*
         * Extract the volume number from the volume header and do various
@@ -385,6 +396,12 @@ hammer_free_volume(hammer_volume_t volume)
                volume->vol_name = NULL;
        }
        if (volume->devvp) {
+               if (vn_isdisk(volume->devvp, NULL) &&
+                   volume->devvp->v_rdev &&
+                   volume->devvp->v_rdev->si_mountpoint == volume->hmp->mp
+               ) {
+                       volume->devvp->v_rdev->si_mountpoint = NULL;
+               }
                vrele(volume->devvp);
                volume->devvp = NULL;
        }
index ae07554..639532b 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/hammer/hammer_vnops.c,v 1.27 2008/02/05 20:52:01 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_vnops.c,v 1.28 2008/02/06 08:59:28 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -230,7 +230,8 @@ hammer_vop_read(struct vop_read_args *ap)
                        bqrelse(bp);
                        break;
                }
-               if ((ip->flags & HAMMER_INODE_RO) == 0) {
+               if ((ip->flags & HAMMER_INODE_RO) == 0 &&
+                   (ip->hmp->mp->mnt_flag & MNT_NOATIME) == 0) {
                        ip->ino_rec.ino_atime = trans.tid;
                        hammer_modify_inode(&trans, ip, HAMMER_INODE_ITIMES);
                }
@@ -701,6 +702,12 @@ hammer_vop_nresolve(struct vop_nresolve_args *ap)
  * locked.  A parent_obj_id of 0 does not necessarily indicate that we are
  * at the root, instead it could indicate that the directory we were in was
  * removed.
+ *
+ * NOTE: as-of sequences are not linked into the directory structure.  If
+ * we are at the root with a different asof then the mount point, reload
+ * the same directory with the mount point's asof.   I'm not sure what this
+ * will do to NFS.  We encode ASOF stamps in NFS file handles so it might not
+ * get confused, but it hasn't been tested.
  */
 static
 int
@@ -708,17 +715,30 @@ hammer_vop_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
 {
        struct hammer_inode *dip;
        struct hammer_inode *ip;
-       u_int64_t parent_obj_id;
+       int64_t parent_obj_id;
+       hammer_tid_t asof;
        int error;
 
        dip = VTOI(ap->a_dvp);
-       if ((parent_obj_id = dip->ino_data.parent_obj_id) == 0) {
-               *ap->a_vpp = NULL;
-               return ENOENT;
+       asof = dip->obj_asof;
+       parent_obj_id = dip->ino_data.parent_obj_id;
+
+       if (parent_obj_id == 0) {
+               if (dip->obj_id == HAMMER_OBJID_ROOT &&
+                  asof != dip->hmp->asof) {
+                       parent_obj_id = dip->obj_id;
+                       asof = dip->hmp->asof;
+                       *ap->a_fakename = kmalloc(19, M_TEMP, M_WAITOK);
+                       ksnprintf(*ap->a_fakename, 19, "0x%016llx",
+                                  dip->obj_asof);
+               } else {
+                       *ap->a_vpp = NULL;
+                       return ENOENT;
+               }
        }
 
        ip = hammer_get_inode(dip->hmp, &dip->cache[1], parent_obj_id,
-                             dip->obj_asof, dip->flags, &error);
+                             asof, dip->flags, &error);
        if (ip == NULL) {
                *ap->a_vpp = NULL;
                return(error);
@@ -1164,10 +1184,19 @@ hammer_vop_nrename(struct vop_nrename_args *ap)
        /*
         * Remove tncp from the target directory and then link ip as
         * tncp. XXX pass trans to dounlink
+        *
+        * Force the inode sync-time to match the transaction so it is
+        * in-sync with the creation of the target directory entry.
         */
        error = hammer_dounlink(ap->a_tnch, ap->a_tdvp, ap->a_cred, 0);
-       if (error == 0 || error == ENOENT)
+       if (error == 0 || error == ENOENT) {
                error = hammer_ip_add_directory(&trans, tdip, tncp, ip);
+               if (error == 0) {
+                       ip->ino_data.parent_obj_id = tdip->obj_id;
+                       hammer_modify_inode(&trans, ip,
+                               HAMMER_INODE_DDIRTY | HAMMER_INODE_TIDLOCKED);
+               }
+       }
        if (error)
                goto failed; /* XXX */
 
@@ -1469,6 +1498,14 @@ hammer_vop_nsymlink(struct vop_nsymlink_args *ap)
                        /* will be reallocated by routine below */
                }
                error = hammer_ip_add_record(&trans, record);
+
+               /*
+                * Set the file size to the length of the link.
+                */
+               if (error == 0) {
+                       nip->ino_rec.ino_size = bytes;
+                       hammer_modify_inode(&trans, nip, HAMMER_INODE_RDIRTY);
+               }
        }
 
        /*