ceph: perform lazy reads when file mode and caps permit
Sage Weil [Thu, 27 May 2010 17:40:43 +0000 (10:40 -0700)]
If the file mode is marked as "lazy," perform cached/buffered reads when
the caps permit it.  Adjust the rdcache_gen and invalidation logic
accordingly so that we manage our cache based on the FILE_CACHE -or-
FILE_LAZYIO cap bits.

Signed-off-by: Sage Weil <sage@newdream.net>

fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/file.c
fs/ceph/inode.c

index d9c60b8..e00797e 100644 (file)
@@ -552,7 +552,7 @@ static void writepages_finish(struct ceph_osd_request *req,
                 * page truncation thread, possibly losing some data that
                 * raced its way in
                 */
-               if ((issued & CEPH_CAP_FILE_CACHE) == 0)
+               if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0)
                        generic_error_remove_page(inode->i_mapping, page);
 
                unlock_page(page);
index 1a70a3e..b28915d 100644 (file)
@@ -482,8 +482,8 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
         * Each time we receive FILE_CACHE anew, we increment
         * i_rdcache_gen.
         */
-       if ((issued & CEPH_CAP_FILE_CACHE) &&
-           (had & CEPH_CAP_FILE_CACHE) == 0)
+       if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
+           (had & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0)
                ci->i_rdcache_gen++;
 
        /*
@@ -1509,11 +1509,13 @@ retry_locked:
            ci->i_wrbuffer_ref == 0 &&               /* no dirty pages... */
            ci->i_rdcache_gen &&                     /* may have cached pages */
            (file_wanted == 0 ||                     /* no open files */
-            (revoking & CEPH_CAP_FILE_CACHE)) &&     /*  or revoking cache */
+            (revoking & (CEPH_CAP_FILE_CACHE|
+                         CEPH_CAP_FILE_LAZYIO))) && /*  or revoking cache */
            !tried_invalidate) {
                dout("check_caps trying to invalidate on %p\n", inode);
                if (try_nonblocking_invalidate(inode) < 0) {
-                       if (revoking & CEPH_CAP_FILE_CACHE) {
+                       if (revoking & (CEPH_CAP_FILE_CACHE|
+                                       CEPH_CAP_FILE_LAZYIO)) {
                                dout("check_caps queuing invalidate\n");
                                queue_invalidate = 1;
                                ci->i_rdcache_revoking = ci->i_rdcache_gen;
@@ -2276,7 +2278,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
         * try to invalidate (once).  (If there are dirty buffers, we
         * will invalidate _after_ writeback.)
         */
-       if (((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) &&
+       if (((cap->issued & ~newcaps) & (CEPH_CAP_FILE_CACHE|
+                                        CEPH_CAP_FILE_LAZYIO)) &&
            !ci->i_wrbuffer_ref) {
                if (try_nonblocking_invalidate(inode) == 0) {
                        revoked_rdcache = 1;
@@ -2374,7 +2377,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                        writeback = 1; /* will delay ack */
                else if (dirty & ~newcaps)
                        check_caps = 1;  /* initiate writeback in check_caps */
-               else if (((used & ~newcaps) & CEPH_CAP_FILE_CACHE) == 0 ||
+               else if (((used & ~newcaps) & (CEPH_CAP_FILE_CACHE|
+                                              CEPH_CAP_FILE_LAZYIO)) == 0 ||
                           revoked_rdcache)
                        check_caps = 2;     /* send revoke ack in check_caps */
                cap->issued = newcaps;
index 85c86ed..2329244 100644 (file)
@@ -740,28 +740,32 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
                             unsigned long nr_segs, loff_t pos)
 {
        struct file *filp = iocb->ki_filp;
+       struct ceph_file_info *fi = filp->private_data;
        loff_t *ppos = &iocb->ki_pos;
        size_t len = iov->iov_len;
        struct inode *inode = filp->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        void *base = iov->iov_base;
        ssize_t ret;
-       int got = 0;
+       int want, got = 0;
        int checkeof = 0, read = 0;
 
        dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n",
             inode, ceph_vinop(inode), pos, (unsigned)len, inode);
 again:
        __ceph_do_pending_vmtruncate(inode);
-       ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, CEPH_CAP_FILE_CACHE,
-                           &got, -1);
+       if (fi->fmode & CEPH_FILE_MODE_LAZY)
+               want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
+       else
+               want = CEPH_CAP_FILE_CACHE;
+       ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1);
        if (ret < 0)
                goto out;
        dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
             inode, ceph_vinop(inode), pos, (unsigned)len,
             ceph_cap_string(got));
 
-       if ((got & CEPH_CAP_FILE_CACHE) == 0 ||
+       if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
            (iocb->ki_filp->f_flags & O_DIRECT) ||
            (inode->i_sb->s_flags & MS_SYNCHRONOUS))
                /* hmm, this isn't really async... */
index 389f9db..5d893d3 100644 (file)
@@ -442,8 +442,9 @@ int ceph_fill_file_size(struct inode *inode, int issued,
                         * the file is either opened or mmaped
                         */
                        if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD|
-                                     CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
-                                     CEPH_CAP_FILE_EXCL)) ||
+                                      CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
+                                      CEPH_CAP_FILE_EXCL|
+                                      CEPH_CAP_FILE_LAZYIO)) ||
                            mapping_mapped(inode->i_mapping) ||
                            __ceph_caps_file_wanted(ci)) {
                                ci->i_truncate_pending++;