HAMMER - Add MPSAFE suppor for hammer_vop_read().
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 14 Jul 2009 03:46:45 +0000 (20:46 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 14 Jul 2009 03:46:45 +0000 (20:46 -0700)
This is still a bit of a hack.  If vfs.read_mpsafe is set HAMMER will
run MPSAFE for reads from regular files which are cached in the buffer
cache.  Data which is not cached will fall-back to getting the MP lock.

At the moment enabling this operation will cause atime to not get updated
on fully cached files, because the rest of HAMMER is not MPSAFE yet so I
cannot modify the internal hammer_inode state.

sys/vfs/hammer/hammer_inode.c
sys/vfs/hammer/hammer_vnops.c

index 4a4c306..dbdaaf2 100644 (file)
@@ -275,6 +275,12 @@ hammer_get_vnode(struct hammer_inode *ip, struct vnode **vpp)
                        case HAMMER_OBJTYPE_FIFO:
                                vp->v_ops = &hmp->mp->mnt_vn_fifo_ops;
                                break;
+                       case HAMMER_OBJTYPE_REGFILE:
+                               /*
+                                * MPSAFE read supported.
+                                */
+                               vp->v_flag |= VMP_READ;
+                               break;
                        default:
                                break;
                        }
index b73f67c..00ae528 100644 (file)
@@ -213,6 +213,8 @@ hammer_vop_fsync(struct vop_fsync_args *ap)
 
 /*
  * hammer_vop_read { vp, uio, ioflag, cred }
+ *
+ * MPALMOSTSAFE
  */
 static
 int
@@ -228,6 +230,7 @@ hammer_vop_read(struct vop_read_args *ap)
        int seqcount;
        int ioseqcount;
        int blksize;
+       int got_mplock = curthread->td_mpcount;
 
        if (ap->a_vp->v_type != VREG)
                return (EINVAL);
@@ -244,12 +247,14 @@ hammer_vop_read(struct vop_read_args *ap)
        if (seqcount < ioseqcount)
                seqcount = ioseqcount;
 
-       hammer_start_transaction(&trans, ip->hmp);
-
        /*
         * Access the data typically in HAMMER_BUFSIZE blocks via the
         * buffer cache, but HAMMER may use a variable block size based
         * on the offset.
+        *
+        * XXX Temporary hack, delay the start transaction while we remain
+        *     MPSAFE.  NOTE: ino_data.size cannot change while vnode is
+        *     locked-shared.
         */
        while (uio->uio_resid > 0 && uio->uio_offset < ip->ino_data.size) {
                int64_t base_offset;
@@ -259,6 +264,24 @@ hammer_vop_read(struct vop_read_args *ap)
                offset = (int)uio->uio_offset & (blksize - 1);
                base_offset = uio->uio_offset - offset;
 
+               /*
+                * MPSAFE
+                */
+               bp = getcacheblk(ap->a_vp, base_offset);
+               if (bp) {
+                       error = 0;
+                       goto skip;
+               }
+
+               /*
+                * MPUNSAFE
+                */
+               if (got_mplock == 0) {
+                       got_mplock = 1;
+                       get_mplock();
+                       hammer_start_transaction(&trans, ip->hmp);
+               }
+
                if (hammer_cluster_enable) {
                        /*
                         * Use file_limit to prevent cluster_read() from
@@ -282,6 +305,7 @@ hammer_vop_read(struct vop_read_args *ap)
                        brelse(bp);
                        break;
                }
+skip:
 
                /* bp->b_flags |= B_CLUSTEROK; temporarily disabled */
                n = blksize - offset;
@@ -298,12 +322,20 @@ hammer_vop_read(struct vop_read_args *ap)
                        break;
                hammer_stats_file_read += n;
        }
-       if ((ip->flags & HAMMER_INODE_RO) == 0 &&
-           (ip->hmp->mp->mnt_flag & MNT_NOATIME) == 0) {
-               ip->ino_data.atime = trans.time;
-               hammer_modify_inode(ip, HAMMER_INODE_ATIME);
+
+       /*
+        * XXX only update the atime if we had to get the MP lock.
+        * XXX hack hack hack, fixme.
+        */
+       if (got_mplock) {
+               if ((ip->flags & HAMMER_INODE_RO) == 0 &&
+                   (ip->hmp->mp->mnt_flag & MNT_NOATIME) == 0) {
+                       ip->ino_data.atime = trans.time;
+                       hammer_modify_inode(ip, HAMMER_INODE_ATIME);
+               }
+               hammer_done_transaction(&trans);
+               rel_mplock();
        }
-       hammer_done_transaction(&trans);
        return (error);
 }