]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
kclient: more truncate tomfoolery
authorSage Weil <sage@newdream.net>
Fri, 2 May 2008 17:40:46 +0000 (10:40 -0700)
committerSage Weil <sage@newdream.net>
Fri, 2 May 2008 17:40:46 +0000 (10:40 -0700)
src/kernel/file.c
src/kernel/inode.c
src/kernel/super.c
src/kernel/super.h

index 509b302afbe6a0a495273bb2b48a807590cf3869..03641da6331a53dc166cbacbb157e85751325d8a 100644 (file)
@@ -249,6 +249,8 @@ ssize_t ceph_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
        ssize_t ret;
        int got = 0;
 
+       __ceph_do_pending_vmtruncate(inode);
+
        dout(10, "read %llx %llu~%u trying to get caps on %p\n",
             ceph_ino(inode), *ppos, (unsigned)len, inode);
        ret = wait_event_interruptible(ci->i_cap_wq,
@@ -285,6 +287,8 @@ ssize_t ceph_write(struct file *filp, const char __user *buf,
        int check = 0;
        loff_t endoff = *ppos + len;
 
+       __ceph_do_pending_vmtruncate(inode);
+
        /* do we need to explicitly request a larger max_size? */
        spin_lock(&inode->i_lock);
        if ((endoff >= ci->i_max_size ||
index f9e9fa1575cd3941b03e647b58c542bd58d4b3d7..c8cc5b1b3dd7290a1517390bd0c466a63270156c 100644 (file)
@@ -1086,35 +1086,60 @@ void ceph_vmtruncate_work(struct work_struct *work)
        struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
                                                  i_vmtruncate_work);
        struct inode *inode = &ci->vfs_inode;
-
+       
        dout(10, "vmtruncate_work %p\n", inode);
        mutex_lock(&inode->i_mutex);
-       if (inode->i_size < ci->i_vmtruncate_from)
-               vmtruncate(inode, inode->i_size);
+       __ceph_do_pending_vmtruncate(inode);
        mutex_unlock(&inode->i_mutex);
 }
 
+void __ceph_do_pending_vmtruncate(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       loff_t to;
+
+       spin_lock(&inode->i_lock);
+       to = ci->i_vmtruncate_to;
+       ci->i_vmtruncate_to = -1;
+       spin_unlock(&inode->i_lock);
+
+       if (to >= 0) {
+               dout(10, "__do_pending_vmtruncate %p to %lld\n", inode, to);
+               vmtruncate(inode, to);
+       } else
+               dout(10, "__do_pending_vmtruncate %p nothing to do\n", inode);
+}
+
 static void apply_cap_truncate(struct inode *inode, loff_t size)
 {
        struct ceph_client *client = ceph_client(inode->i_sb);
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int queue = 0;
+       int queue_trunc = 0;
 
+       spin_lock(&inode->i_lock);
        /*
         * vmtruncate lazily; we can't block on i_mutex in the message
         * handler path, or we deadlock against osd op replies needed
         * to complete the writes holding the lock...
+        *
+        * if its an expansion, and there is no truncate pending, we
+        * don't need to truncate.
         */
-       spin_lock(&inode->i_lock);
-       if (size < inode->i_size) {
-               ci->i_vmtruncate_from = inode->i_size;
-               queue = 1;
+       if (ci->i_vmtruncate_to < 0 && size > inode->i_size)
+               dout(10, "clean fwd truncate, no vmtruncate needed\n");
+       else if (ci->i_vmtruncate_to >= 0 && size >= ci->i_vmtruncate_to)
+               dout(10, "trunc to %lld < %lld already queued\n", 
+                    ci->i_vmtruncate_to, size);
+       else {
+               /* we need to trunc even smaller */
+               dout(10, "queueing trunc %lld -> %lld\n", inode->i_size, size);
+               ci->i_vmtruncate_to = size;
+               queue_trunc = 1;
        }
        i_size_write(inode, size);
        ci->i_reported_size = size;
        spin_unlock(&inode->i_lock);
-
-       if (queue)
+       if (queue_trunc)
                queue_work(client->trunc_wq, &ci->i_vmtruncate_work);
 }
 
@@ -1437,6 +1462,7 @@ static int ceph_setattr_size(struct dentry *dentry, struct iattr *attr)
        err = ceph_mdsc_do_request(mdsc, req);
        ceph_mdsc_put_request(req);
        dout(10, "truncate result %d\n", err);
+       __ceph_do_pending_vmtruncate(inode);
        if (err)
                return err;
 
@@ -1450,6 +1476,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        const unsigned int ia_valid = attr->ia_valid;
        int err;
 
+       __ceph_do_pending_vmtruncate(inode);
+
        err = inode_change_ok(inode, attr);
        if (err != 0)
                return err;
index b57d47ed54bf24c3244a83156bb5de145720048d..d56a99494ca3f9401656c3275cebfb8e8cd5c315 100644 (file)
@@ -177,6 +177,8 @@ static struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_hashval = 0;
 
        INIT_WORK(&ci->i_wb_work, ceph_inode_writeback);
+
+       ci->i_vmtruncate_to = -1;
        INIT_WORK(&ci->i_vmtruncate_work, ceph_vmtruncate_work);
 
        return &ci->vfs_inode;
index 05afc0d35956704fe2d2b382a86f42f3d253ce4b..2f599f30c1dc6ec067741aa9b18c07d68a9e2a01 100644 (file)
@@ -199,7 +199,7 @@ struct ceph_inode_info {
 
        struct work_struct i_wb_work;  /* writeback work */
 
-       loff_t i_vmtruncate_from;
+       loff_t i_vmtruncate_to;
        struct work_struct i_vmtruncate_work;
 
        struct inode vfs_inode; /* at end */
@@ -394,6 +394,7 @@ extern void ceph_check_caps(struct ceph_inode_info *ci, int is_delayed);
 extern void ceph_inode_set_size(struct inode *inode, loff_t size);
 extern void ceph_inode_writeback(struct work_struct *work);
 extern void ceph_vmtruncate_work(struct work_struct *work);
+extern void __ceph_do_pending_vmtruncate(struct inode *inode);
 
 extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
 extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,