HAMMER 5/many - in-memory cache and more vnops.
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 20 Nov 2007 22:55:40 +0000 (22:55 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 20 Nov 2007 22:55:40 +0000 (22:55 +0000)
Get more vnops working with the in-memory cache.  Files can now be created,
linked, and deleted.  Directories can be scanned.  NOTE: The topology is
not yet flushed to the media.

sys/vfs/hammer/hammer.h
sys/vfs/hammer/hammer_cursor.c
sys/vfs/hammer/hammer_cursor.h
sys/vfs/hammer/hammer_disk.h
sys/vfs/hammer/hammer_inode.c
sys/vfs/hammer/hammer_object.c
sys/vfs/hammer/hammer_subs.c
sys/vfs/hammer/hammer_vnops.c

index 4c93458..eef3940 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.7 2007/11/20 07:16:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer.h,v 1.8 2007/11/20 22:55:40 dillon Exp $
  */
 /*
  * This header file contains structures used internally by the HAMMERFS
@@ -179,7 +179,6 @@ struct hammer_record {
        struct hammer_inode             *ip;
        union hammer_record_ondisk      rec;
        union hammer_data_ondisk        *data;
-       int32_t                         data_len;
        int                             flags;
 };
 
@@ -440,12 +439,14 @@ hammer_tid_t hammer_alloc_tid(hammer_transaction_t trans);
 hammer_tid_t hammer_alloc_recid(hammer_transaction_t trans);
 
 enum vtype hammer_get_vnode_type(u_int8_t obj_type);
+int hammer_get_dtype(u_int8_t obj_type);
 u_int8_t hammer_get_obj_type(enum vtype vtype);
 int64_t hammer_directory_namekey(void *name, int len);
 
 int    hammer_init_cursor_hmp(hammer_cursor_t cursor, hammer_mount_t hmp);
 int    hammer_init_cursor_ip(hammer_cursor_t cursor, hammer_inode_t ip);
 void   hammer_done_cursor(hammer_cursor_t cursor);
+void   hammer_mem_done(hammer_cursor_t cursor);
 
 int    hammer_btree_lookup(hammer_cursor_t cursor);
 int    hammer_btree_extract(hammer_cursor_t cursor, int flags);
index 4baf855..8823dd7 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_cursor.c,v 1.2 2007/11/20 07:16:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_cursor.c,v 1.3 2007/11/20 22:55:40 dillon Exp $
  */
 
 /*
@@ -123,8 +123,8 @@ hammer_done_cursor(hammer_cursor_t cursor)
                 hammer_rel_buffer(cursor->record_buffer, 0);
                 cursor->record_buffer = NULL;
         }
-       if (cursor->iprec)
-               hammer_rel_mem_record(&cursor->iprec);
+       if (cursor->ip)
+               hammer_mem_done(cursor);
 
        cursor->data = NULL;
        cursor->record = NULL;
index 700725d..28b6928 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_cursor.h,v 1.2 2007/11/20 07:16:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_cursor.h,v 1.3 2007/11/20 22:55:40 dillon Exp $
  */
 
 /*
@@ -93,6 +93,7 @@ struct hammer_cursor {
         */
        struct hammer_inode *ip;
        struct hammer_record *iprec;
+       struct hammer_rec_rb_tree_scan_info scan;
 };
 
 typedef struct hammer_cursor *hammer_cursor_t;
index 54a11c4..b318806 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_disk.h,v 1.7 2007/11/20 07:16:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_disk.h,v 1.8 2007/11/20 22:55:40 dillon Exp $
  */
 
 #ifndef _SYS_UUID_H_
@@ -67,6 +67,8 @@
 typedef u_int64_t hammer_tid_t;
 
 #define HAMMER_MAX_TID 0xFFFFFFFFFFFFFFFFULL
+#define HAMMER_MIN_KEY -0x8000000000000000LL
+#define HAMMER_MAX_KEY 0x7FFFFFFFFFFFFFFFLL
 
 /*
  * Most HAMMER data structures are embedded in 16K filesystem buffers.
@@ -508,8 +510,10 @@ struct hammer_data_record {
  * offset.  A portion of the namekey is an iterator or randomizer to deal
  * with collisions.
  *
- * Note that base.base.obj_type holds the filesystem object type of obj_id,
- * e.g. a den_type equivalent.
+ * NOTE: base.base.obj_type holds the filesystem object type of obj_id,
+ *      e.g. a den_type equivalent.
+ *
+ * NOTE: den_name / the filename data reference is NOT terminated with \0.
  *
  */
 struct hammer_entry_record {
index d8d9c94..ea7d1ad 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.5 2007/11/20 07:16:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_inode.c,v 1.6 2007/11/20 22:55:40 dillon Exp $
  */
 
 #include "hammer.h"
@@ -235,11 +235,11 @@ hammer_create_inode(hammer_transaction_t trans, struct vattr *vap,
 {
        hammer_mount_t hmp;
        hammer_inode_t ip;
+       uid_t xuid;
 
        hmp = trans->hmp;
        ip = kmalloc(sizeof(*ip), M_HAMMER, M_WAITOK|M_ZERO);
        ip->obj_id = hammer_alloc_tid(trans);
-       kprintf("object id %llx\n", ip->obj_id);
        KKASSERT(ip->obj_id != 0);
        ip->obj_asof = HAMMER_MAX_TID;  /* XXX */
        ip->hmp = hmp;
@@ -268,13 +268,24 @@ hammer_create_inode(hammer_transaction_t trans, struct vattr *vap,
        ip->ino_data.mode = vap->va_mode;
        ip->ino_data.ctime = trans->tid;
        ip->ino_data.parent_obj_id = (dip) ? dip->ino_rec.base.base.obj_id : 0;
+
+       /*
+        * Calculate default uid/gid and overwrite with information from
+        * the vap.
+        */
+       xuid = hammer_to_unix_xid(&dip->ino_data.uid);
+       ip->ino_data.gid = dip->ino_data.gid;
+       xuid = vop_helper_create_uid(hmp->mp, dip->ino_data.mode, xuid, cred,
+                                    &vap->va_mode);
+       ip->ino_data.mode = vap->va_mode;
+
        if (vap->va_vaflags & VA_UID_UUID_VALID)
                ip->ino_data.uid = vap->va_uid_uuid;
-       else
-               hammer_guid_to_uuid(&ip->ino_data.uid, vap->va_uid);
+       else if (vap->va_uid != (uid_t)VNOVAL)
+               hammer_guid_to_uuid(&ip->ino_data.uid, xuid);
        if (vap->va_vaflags & VA_GID_UUID_VALID)
                ip->ino_data.gid = vap->va_gid_uuid;
-       else
+       else if (vap->va_gid != (gid_t)VNOVAL)
                hammer_guid_to_uuid(&ip->ino_data.gid, vap->va_gid);
 
        hammer_ref(&ip->lock);
@@ -287,13 +298,13 @@ hammer_create_inode(hammer_transaction_t trans, struct vattr *vap,
 }
 
 /*
- * Release a reference on an inode and unload it if told to flush
+ * Release a reference on an inode and unload it if told to flush.
  */
 void
 hammer_rel_inode(struct hammer_inode *ip, int flush)
 {
        hammer_unref(&ip->lock);
-       if (flush)
+       if (flush || ip->ino_rec.ino_nlinks == 0)
                ip->flags |= HAMMER_INODE_FLUSH;
        if (ip->lock.refs == 0 && (ip->flags & HAMMER_INODE_FLUSH))
                hammer_unload_inode(ip, NULL);
@@ -311,11 +322,13 @@ hammer_unload_inode(struct hammer_inode *ip, void *data __unused)
                ("hammer_unload_inode: %d refs\n", ip->lock.refs));
        KKASSERT(ip->vp == NULL);
        hammer_ref(&ip->lock);
+
+       /* XXX flush inode to disk */
+       kprintf("flush inode %p\n", ip);
+
        RB_REMOVE(hammer_ino_rb_tree, &ip->hmp->rb_inos_root, ip);
 
        hammer_uncache_node(&ip->cache);
-
-       /* XXX flush */
        kfree(ip, M_HAMMER);
        return(0);
 }
index d9a619d..5b3422f 100644 (file)
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/hammer/hammer_object.c,v 1.3 2007/11/20 07:16:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_object.c,v 1.4 2007/11/20 22:55:40 dillon Exp $
  */
 
 #include "hammer.h"
 
 static int hammer_mem_add(hammer_transaction_t trans,
                             hammer_record_t record);
+static int hammer_mem_lookup(hammer_cursor_t cursor, hammer_inode_t ip);
 static int hammer_mem_search(hammer_cursor_t cursor, hammer_inode_t ip);
 
 /*
@@ -107,6 +108,29 @@ hammer_rec_compare(hammer_base_elm_t info, hammer_record_t rec)
         return(0);
 }
 
+/*
+ * RB_SCAN comparison code for hammer_mem_search().  The argument order
+ * is reversed so the comparison result has to be negated.  key_beg and
+ * key_end are both inclusive boundaries.
+ */
+static
+int
+hammer_rec_scan_cmp(hammer_record_t rec, void *data)
+{
+       hammer_cursor_t cursor = data;
+       int r;
+
+       r = hammer_rec_compare(&cursor->key_beg, rec);
+       if (r > 0)
+               return(-1);
+       if (r == 0)
+               return(0);
+       r = hammer_rec_compare(&cursor->key_end, rec);
+       if (r <= 0)
+               return(1);
+       return(0);
+}
+
 RB_GENERATE(hammer_rec_rb_tree, hammer_record, rb_node, hammer_rec_rb_compare);
 RB_GENERATE_XLOOKUP(hammer_rec_rb_tree, INFO, hammer_record, rb_node,
                    hammer_rec_compare, hammer_base_elm_t);
@@ -148,20 +172,20 @@ hammer_rel_mem_record(struct hammer_record **recordp)
 /*
  * Free a record.  Clean the structure up even though we are throwing it
  * away as a sanity check.  The actual free operation is delayed while
- * the record is referenced.
+ * the record is referenced.  However, the record is removed from the RB
+ * tree immediately.
  */
 void
 hammer_free_mem_record(hammer_record_t record)
 {
-       if (record->lock.refs) {
-               record->flags |= HAMMER_RECF_DELETED;
-               return;
-       }
-
        if (record->flags & HAMMER_RECF_ONRBTREE) {
                RB_REMOVE(hammer_rec_rb_tree, &record->ip->rec_tree, record);
                record->flags &= ~HAMMER_RECF_ONRBTREE;
        }
+       if (record->lock.refs) {
+               record->flags |= HAMMER_RECF_DELETED;
+               return;
+       }
        if (record->flags & HAMMER_RECF_ALLOCDATA) {
                kfree(record->data, M_HAMMER);
                record->flags &= ~HAMMER_RECF_ALLOCDATA;
@@ -174,16 +198,24 @@ hammer_free_mem_record(hammer_record_t record)
  * Lookup an in-memory record given the key specified in the cursor.  Works
  * just like hammer_btree_lookup() but operates on an inode's in-memory
  * record list.
+ *
+ * The lookup must fail if the record is marked for deferred deletion.
  */
 static
 int
-hammer_mem_search(hammer_cursor_t cursor, hammer_inode_t ip)
+hammer_mem_lookup(hammer_cursor_t cursor, hammer_inode_t ip)
 {
        int error;
 
        if (cursor->iprec)
                hammer_rel_mem_record(&cursor->iprec);
+       if (cursor->ip) {
+               hammer_rec_rb_tree_scan_info_done(&cursor->scan,
+                                                 &cursor->ip->rec_tree);
+       }
        cursor->ip = ip;
+       hammer_rec_rb_tree_scan_info_link(&cursor->scan, &ip->rec_tree);
+       cursor->scan.node = NULL;
        cursor->iprec = hammer_rec_rb_tree_RB_LOOKUP_INFO(
                                &ip->rec_tree, &cursor->key_beg);
        if (cursor->iprec == NULL) {
@@ -195,6 +227,61 @@ hammer_mem_search(hammer_cursor_t cursor, hammer_inode_t ip)
        return(error);
 }
 
+/*
+ * hammer_mem_search() - locate the first in-memory record matching the
+ * cursor.
+ *
+ * The RB_SCAN function we use is designed as a callback.  We terminate it
+ * (return -1) as soon as we get a match.
+ */
+static
+int
+hammer_rec_scan_callback(hammer_record_t rec, void *data)
+{
+       hammer_cursor_t cursor = data;
+
+       if (cursor->iprec == NULL) {
+               cursor->iprec = rec;
+               hammer_ref(&rec->lock);
+               return(-1);
+       }
+       return(0);
+}
+
+static
+int
+hammer_mem_search(hammer_cursor_t cursor, hammer_inode_t ip)
+{
+       if (cursor->iprec)
+               hammer_rel_mem_record(&cursor->iprec);
+       if (cursor->ip) {
+               hammer_rec_rb_tree_scan_info_done(&cursor->scan,
+                                                 &cursor->ip->rec_tree);
+       }
+       cursor->ip = ip;
+       hammer_rec_rb_tree_scan_info_link(&cursor->scan, &ip->rec_tree);
+       cursor->scan.node = NULL;
+       hammer_rec_rb_tree_RB_SCAN(&ip->rec_tree, hammer_rec_scan_cmp,
+                                  hammer_rec_scan_callback, cursor);
+       if (cursor->iprec) {
+               cursor->scan.node = hammer_rec_rb_tree_RB_NEXT(cursor->iprec);
+               return(0);
+       }
+       return(ENOENT);
+}
+
+void
+hammer_mem_done(hammer_cursor_t cursor)
+{
+       if (cursor->ip) {
+               hammer_rec_rb_tree_scan_info_done(&cursor->scan,
+                                                 &cursor->ip->rec_tree);
+               cursor->ip = NULL;
+       }
+        if (cursor->iprec)
+               hammer_rel_mem_record(&cursor->iprec);
+}
+
 /************************************************************************
  *                  HAMMER IN-MEMORY RECORD FUNCTIONS                  *
  ************************************************************************
@@ -222,23 +309,26 @@ hammer_ip_add_directory(struct hammer_transaction *trans,
 
        record = hammer_alloc_mem_record(trans, dip);
 
-       bytes = ncp->nc_nlen + 1;
+       bytes = ncp->nc_nlen;   /* NOTE: terminating \0 is NOT included */
+       if (++trans->hmp->namekey_iterator == 0)
+               ++trans->hmp->namekey_iterator;
 
        record->rec.entry.base.base.obj_id = dip->obj_id;
-       record->rec.entry.base.base.key = hammer_directory_namekey(ncp->nc_name, bytes - 1);
-       record->rec.entry.base.base.key += trans->hmp->namekey_iterator++;
+       record->rec.entry.base.base.key =
+               hammer_directory_namekey(ncp->nc_name, bytes);
+       record->rec.entry.base.base.key += trans->hmp->namekey_iterator;
        record->rec.entry.base.base.create_tid = trans->tid;
        record->rec.entry.base.base.rec_type = HAMMER_RECTYPE_DIRENTRY;
        record->rec.entry.base.base.obj_type = ip->ino_rec.base.base.obj_type;
-       record->rec.entry.base.base.obj_id = ip->obj_id;
+       record->rec.entry.obj_id = ip->obj_id;
        if (bytes <= sizeof(record->rec.entry.den_name)) {
                record->data = (void *)record->rec.entry.den_name;
        } else {
                record->data = kmalloc(bytes, M_HAMMER, M_WAITOK);
                record->flags |= HAMMER_RECF_ALLOCDATA;
-               bcopy(ncp->nc_name, record->data, bytes);
        }
-       record->data_len = bytes;
+       bcopy(ncp->nc_name, record->data, bytes);
+       record->rec.entry.base.data_len = bytes;
        ++ip->ino_rec.ino_nlinks;
        hammer_modify_inode(trans, ip, HAMMER_INODE_RDIRTY);
        error = hammer_mem_add(trans, record);
@@ -284,10 +374,17 @@ hammer_ip_del_directory(struct hammer_transaction *trans,
        }
 
        /*
-        * One less link
+        * One less link.  Mark the inode and all of its records as deleted
+        * when the last link goes away.  The inode will be automatically
+        * flushed when its last reference goes away.
         */
        if (error == 0) {
                --ip->ino_rec.ino_nlinks;
+               if (ip->ino_rec.ino_nlinks == 0)
+                       ip->ino_rec.base.base.delete_tid = trans->tid;
+               error = hammer_ip_delete_range(trans, ip,
+                                              HAMMER_MIN_KEY, HAMMER_MAX_KEY);
+               KKASSERT(RB_EMPTY(&ip->rec_tree));
                hammer_modify_inode(trans, ip, HAMMER_INODE_RDIRTY);
        }
        return(error);
@@ -353,7 +450,7 @@ hammer_ip_lookup(hammer_cursor_t cursor, struct hammer_inode *ip)
         * If the element is in-memory return it without searching the
         * on-disk B-Tree
         */
-       error = hammer_mem_search(cursor, ip);
+       error = hammer_mem_lookup(cursor, ip);
        if (error == 0) {
                cursor->record = &cursor->iprec->rec;
                return(error);
@@ -388,7 +485,7 @@ hammer_ip_first(hammer_cursor_t cursor, struct hammer_inode *ip)
        /*
         * Clean up fields and setup for merged scan
         */
-       cursor->flags &= ~(HAMMER_CURSOR_ATEDISK | HAMMER_CURSOR_ATEMEM);
+       cursor->flags |= HAMMER_CURSOR_ATEDISK | HAMMER_CURSOR_ATEMEM;
        cursor->flags |= HAMMER_CURSOR_DISKEOF | HAMMER_CURSOR_MEMEOF;
        if (cursor->iprec)
                hammer_rel_mem_record(&cursor->iprec);
@@ -400,8 +497,10 @@ hammer_ip_first(hammer_cursor_t cursor, struct hammer_inode *ip)
                error = hammer_btree_lookup(cursor);
                if (error && error != ENOENT)
                        return(error);
-               if (error == 0)
-                       cursor->flags &= ~HAMMER_CURSOR_DISKEOF;
+               if (error == 0) {
+                       cursor->flags &= ~HAMMER_CURSOR_DISKEOF ;
+                       cursor->flags &= ~HAMMER_CURSOR_ATEDISK ;
+               }
        }
 
        /*
@@ -410,8 +509,10 @@ hammer_ip_first(hammer_cursor_t cursor, struct hammer_inode *ip)
        error = hammer_mem_search(cursor, ip);
        if (error && error != ENOENT)
                return(error);
-       if (error == 0)
+       if (error == 0) {
                cursor->flags &= ~HAMMER_CURSOR_MEMEOF;
+               cursor->flags &= ~HAMMER_CURSOR_ATEMEM;
+       }
 
        /*
         * This will return the first matching record.
@@ -452,18 +553,18 @@ hammer_ip_next(hammer_cursor_t cursor)
        }
 
        /*
-        * Get the next in-memory record.  Records marked for defered
-        * deletion must be skipped.
+        * Get the next in-memory record.  The record can be ripped out
+        * of the RB tree so we maintain a scan_info structure to track
+        * the next node.
         */
        if (cursor->flags & HAMMER_CURSOR_ATEMEM) {
                if ((cursor->flags & HAMMER_CURSOR_MEMEOF) == 0) {
-                       rec = cursor->iprec;
-                       do {
-                               rec = hammer_rec_rb_tree_RB_NEXT(rec);
-                       } while(rec && (rec->flags & HAMMER_RECF_DELETED));
+                       rec = cursor->scan.node;        /* next node */
                        if (rec) {
                                cursor->flags &= ~HAMMER_CURSOR_ATEMEM;
                                hammer_ref(&rec->lock);
+                               cursor->scan.node =
+                                       hammer_rec_rb_tree_RB_NEXT(rec);
                        } else {
                                cursor->flags |= HAMMER_CURSOR_MEMEOF;
                        }
@@ -477,7 +578,7 @@ hammer_ip_next(hammer_cursor_t cursor)
         * relative position.
         */
        error = 0;
-       switch(cursor->flags & (HAMMER_CURSOR_DISKEOF | HAMMER_CURSOR_MEMEOF)) {
+       switch(cursor->flags & (HAMMER_CURSOR_ATEDISK | HAMMER_CURSOR_ATEMEM)) {
        case 0:
                /*
                 * Both entries valid
@@ -492,14 +593,14 @@ hammer_ip_next(hammer_cursor_t cursor)
                        break;
                }
                /* fall through to the memory entry */
-       case HAMMER_CURSOR_DISKEOF:
+       case HAMMER_CURSOR_ATEDISK:
                /*
                 * Only the memory entry is valid
                 */
                cursor->record = &cursor->iprec->rec;
                cursor->flags |= HAMMER_CURSOR_ATEMEM;
                break;
-       case HAMMER_CURSOR_MEMEOF:
+       case HAMMER_CURSOR_ATEMEM:
                /*
                 * Only the disk entry is valid
                 */
index 5c0e52d..9a7f3e3 100644 (file)
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/hammer/hammer_subs.c,v 1.4 2007/11/20 07:16:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_subs.c,v 1.5 2007/11/20 22:55:40 dillon Exp $
  */
 /*
  * HAMMER structural locking
  */
 
 #include "hammer.h"
+#include <sys/dirent.h>
 
 void
 hammer_lock_ex(struct hammer_lock *lock)
@@ -210,6 +211,30 @@ hammer_get_vnode_type(u_int8_t obj_type)
        /* not reached */
 }
 
+int
+hammer_get_dtype(u_int8_t obj_type)
+{
+       switch(obj_type) {
+       case HAMMER_OBJTYPE_DIRECTORY:
+               return(DT_DIR);
+       case HAMMER_OBJTYPE_REGFILE:
+               return(DT_REG);
+       case HAMMER_OBJTYPE_DBFILE:
+               return(DT_DBF);
+       case HAMMER_OBJTYPE_FIFO:
+               return(DT_FIFO);
+       case HAMMER_OBJTYPE_CDEV:
+               return(DT_CHR);
+       case HAMMER_OBJTYPE_BDEV:
+               return(DT_BLK);
+       case HAMMER_OBJTYPE_SOFTLINK:
+               return(DT_LNK);
+       default:
+               return(DT_UNKNOWN);
+       }
+       /* not reached */
+}
+
 u_int8_t
 hammer_get_obj_type(enum vtype vtype)
 {
@@ -239,13 +264,16 @@ hammer_get_obj_type(enum vtype vtype)
  * crc in the MSB and 0 in the LSB.  The caller will use the low bits to
  * generate a unique key and will scan all entries with the same upper
  * 32 bits when issuing a lookup.
+ *
+ * We strip bit 63 in order to provide a positive key, this way a seek
+ * offset of 0 will represent the base of the directory.
  */
 int64_t
 hammer_directory_namekey(void *name, int len)
 {
        int64_t key;
 
-       key = (int64_t)crc32(name, len) << 32;
+       key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32;
        return(key);
 }
 
index 011948c..09b55b0 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.4 2007/11/20 07:16:28 dillon Exp $
+ * $DragonFly: src/sys/vfs/hammer/hammer_vnops.c,v 1.5 2007/11/20 22:55:40 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -559,6 +559,8 @@ hammer_vop_nlink(struct vop_nlink_args *ap)
        if (error) {
                hammer_abort_transaction(&trans);
        } else {
+               cache_setunresolved(nch);
+               cache_setvp(nch, ap->a_vp);
                hammer_commit_transaction(&trans);
        }
        return (error);
@@ -716,14 +718,101 @@ hammer_vop_print(struct vop_print_args *ap)
 }
 
 /*
- * hammer_vop_readdir { vp, uio, cred, *eofflag }
+ * hammer_vop_readdir { vp, uio, cred, *eofflag, *ncookies, off_t **cookies }
  */
 static
 int
 hammer_vop_readdir(struct vop_readdir_args *ap)
 {
-       kprintf("hammer_vop_readdir\n");
-       return EOPNOTSUPP;
+       struct hammer_cursor cursor;
+       struct hammer_inode *ip;
+       struct uio *uio;
+       hammer_record_ondisk_t rec;
+       hammer_base_elm_t base;
+       int error;
+       int cookie_index;
+       int ncookies;
+       off_t *cookies;
+       off_t saveoff;
+       int r;
+
+       ip = VTOI(ap->a_vp);
+       uio = ap->a_uio;
+       hammer_init_cursor_ip(&cursor, ip);
+
+       /*
+        * Key range (begin and end inclusive) to scan.  Directory keys
+        * directly translate to a 64 bit 'seek' position.
+        */
+       cursor.key_beg.obj_id = ip->obj_id;
+       cursor.key_beg.create_tid = ip->obj_asof;
+       cursor.key_beg.delete_tid = 0;
+        cursor.key_beg.rec_type = HAMMER_RECTYPE_DIRENTRY;
+       cursor.key_beg.obj_type = 0;
+       cursor.key_beg.key = uio->uio_offset;
+
+       cursor.key_end = cursor.key_beg;
+       cursor.key_end.key = HAMMER_MAX_KEY;
+
+       if (ap->a_ncookies) {
+               ncookies = uio->uio_resid / 16 + 1;
+               if (ncookies > 1024)
+                       ncookies = 1024;
+               cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
+               cookie_index = 0;
+       } else {
+               ncookies = -1;
+               cookies = NULL;
+               cookie_index = 0;
+       }
+
+       saveoff = cursor.key_beg.key;
+       error = hammer_ip_first(&cursor, ip);
+
+       while (error == 0) {
+               error = hammer_ip_resolve_data(&cursor);
+               if (error)
+                       break;
+               rec = cursor.record;
+               base = &rec->base.base;
+               saveoff = base->key;
+
+               r = vop_write_dirent(
+                            &error, uio, rec->entry.obj_id,
+                            rec->entry.base.data_len,
+                            hammer_get_dtype(rec->entry.base.base.obj_type),
+                            (void *)cursor.data);
+               if (r)
+                       break;
+               ++saveoff;
+               if (cookies)
+                       cookies[cookie_index] = base->key;
+               ++cookie_index;
+               if (cookie_index == ncookies)
+                       break;
+               error = hammer_ip_next(&cursor);
+       }
+       hammer_done_cursor(&cursor);
+
+       if (ap->a_eofflag)
+               *ap->a_eofflag = (error == ENOENT);
+       if (error == ENOENT)
+               error = 0;
+       uio->uio_offset = saveoff;
+       if (error && cookie_index == 0) {
+               if (cookies) {
+                       kfree(cookies, M_TEMP);
+                       *ap->a_ncookies = 0;
+                       *ap->a_cookies = NULL;
+               }
+       } else {
+               error = 0;
+               if (cookies) {
+                       *ap->a_ncookies = cookie_index;
+                       *ap->a_cookies = cookies;
+               }
+       }
+       return(error);
 }
 
 /*
@@ -900,14 +989,14 @@ hammer_vop_setattr(struct vop_setattr_args *ap)
        }
        if (vap->va_uid != (uid_t)VNOVAL) {
                hammer_guid_to_uuid(&uuid, vap->va_uid);
-               if (bcmp(&uuid, &ip->ino_data.uid, sizeof(uuid)) == 0) {
+               if (bcmp(&uuid, &ip->ino_data.uid, sizeof(uuid)) != 0) {
                        ip->ino_data.uid = uuid;
                        modflags |= HAMMER_INODE_DDIRTY;
                }
        }
        if (vap->va_gid != (uid_t)VNOVAL) {
-               hammer_guid_to_uuid(&uuid, vap->va_uid);
-               if (bcmp(&uuid, &ip->ino_data.gid, sizeof(uuid)) == 0) {
+               hammer_guid_to_uuid(&uuid, vap->va_gid);
+               if (bcmp(&uuid, &ip->ino_data.gid, sizeof(uuid)) != 0) {
                        ip->ino_data.gid = uuid;
                        modflags |= HAMMER_INODE_DDIRTY;
                }
@@ -1197,7 +1286,6 @@ hammer_dounlink(struct nchandle *nch, struct vnode *dvp, struct ucred *cred,
        hammer_inode_t ip;
        hammer_record_ondisk_t rec;
        struct hammer_cursor cursor;
-       struct vnode *vp;
        int64_t namekey;
        int error;
 
@@ -1263,11 +1351,7 @@ hammer_dounlink(struct nchandle *nch, struct vnode *dvp, struct ucred *cred,
                }
                hammer_rel_inode(ip, 0);
 
-               error = hammer_vfs_vget(dip->hmp->mp, rec->entry.obj_id, &vp);
                if (error == 0) {
-                       vn_unlock(vp);
-                       cache_setvp(nch, vp);
-                       vrele(vp);
                        hammer_commit_transaction(&trans);
                } else {
                        hammer_abort_transaction(&trans);