Whamcloud - gitweb
LU-417 llite: report non-zero blocks on writing client
authorBobi Jam <bobijam@whamcloud.com>
Fri, 4 Nov 2011 07:22:41 +0000 (15:22 +0800)
committerOleg Drokin <green@whamcloud.com>
Sat, 31 Dec 2011 08:50:41 +0000 (03:50 -0500)
Writing client may not report accurate allocated block numbers when
dirty pages has not been writting back to OSTs, some "cp" or "tar" may
skip the file because it thinks it is completely sparse.

This patch makes writing client consider dirty pages when reporting
allocated blocks, lest the file be treated as a completely sparse one.

Signed-off-by: Bobi Jam <bobijam@whamcloud.com>
Change-Id: I985d50a44ea1e917bf8e1cba3b5cb770eec35c3f
Reviewed-on: http://review.whamcloud.com/1647
Tested-by: Hudson
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/lclient.h
lustre/lclient/glimpse.c
lustre/lclient/lcommon_cl.c
lustre/obdfilter/filter_lvb.c

index 87361eb..adc4b5a 100644 (file)
@@ -43,6 +43,8 @@
 #ifndef LCLIENT_H
 #define LCLIENT_H
 
+blkcnt_t dirty_cnt(struct inode *inode);
+
 int cl_glimpse_size(struct inode *inode);
 int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
                     struct inode *inode, struct cl_object *clob);
index 1045c1b..c95ccce 100644 (file)
@@ -80,6 +80,30 @@ static const struct cl_lock_descr whole_file = {
         .cld_mode  = CLM_READ
 };
 
+/*
+ * Check whether file has possible unwriten pages.
+ *
+ * \retval 1    file is mmap-ed or has dirty pages
+ *         0    otherwise
+ */
+blkcnt_t dirty_cnt(struct inode *inode)
+{
+        blkcnt_t cnt = 0;
+#ifdef __KERNEL__
+        struct ccc_object *vob = cl_inode2ccc(inode);
+        void              *results[1];
+
+        if (inode->i_mapping != NULL)
+                cnt += radix_tree_gang_lookup_tag(&inode->i_mapping->page_tree,
+                                                  results, 0, 1,
+                                                  PAGECACHE_TAG_DIRTY);
+        if (cnt == 0 && cfs_atomic_read(&vob->cob_mmap_cnt) > 0)
+                cnt = 1;
+
+#endif
+        return (cnt > 0) ? 1 : 0;
+}
+
 int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
                     struct inode *inode, struct cl_object *clob)
 {
@@ -124,18 +148,29 @@ int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
                         lock = cl_lock_request(env, io, descr, "glimpse",
                                                cfs_current());
                         cio->cui_glimpse = 0;
-                        if (!IS_ERR(lock)) {
-                                result = cl_wait(env, lock);
-                                if (result == 0) {
-                                        cl_merge_lvb(inode);
-                                        cl_unuse(env, lock);
+
+                        if (IS_ERR(lock))
+                                RETURN(PTR_ERR(lock));
+
+                        result = cl_wait(env, lock);
+                        if (result == 0) {
+                                cl_merge_lvb(inode);
+                                if (cl_isize_read(inode) > 0 &&
+                                    inode->i_blocks == 0) {
+                                        /*
+                                         * LU-417: Add dirty pages block count
+                                         * lest i_blocks reports 0, some "cp" or
+                                         * "tar" may think it's a completely
+                                         * sparse file and skip it.
+                                         */
+                                        inode->i_blocks = dirty_cnt(inode);
                                 }
-                                cl_lock_release(env, lock,
-                                                "glimpse", cfs_current());
-                        } else
-                                result = PTR_ERR(lock);
-                } else
+                                cl_unuse(env, lock);
+                        }
+                        cl_lock_release(env, lock, "glimpse", cfs_current());
+                } else {
                         CDEBUG(D_DLMTRACE, "No objects for inode\n");
+                }
         }
 
         RETURN(result);
index 16d7fbd..35b1455 100644 (file)
@@ -441,6 +441,13 @@ int ccc_object_glimpse(const struct lu_env *env,
         lvb->lvb_mtime = cl_inode_mtime(inode);
         lvb->lvb_atime = cl_inode_atime(inode);
         lvb->lvb_ctime = cl_inode_ctime(inode);
+        /*
+         * LU-417: Add dirty pages block count lest i_blocks reports 0, some
+         * "cp" or "tar" on remote node may think it's a completely sparse file
+         * and skip it.
+         */
+        if (lvb->lvb_size > 0 && lvb->lvb_blocks == 0)
+                lvb->lvb_blocks = dirty_cnt(inode);
         RETURN(0);
 }
 
index 080db86..1a614f2 100644 (file)
@@ -188,6 +188,12 @@ static int filter_lvbo_update(struct ldlm_resource *res,
                                lvb->lvb_ctime, new->lvb_ctime);
                         lvb->lvb_ctime = new->lvb_ctime;
                 }
+                if (new->lvb_blocks > lvb->lvb_blocks || !increase_only) {
+                        CDEBUG(D_DLMTRACE, "res: "LPU64" updating lvb blocks: "
+                               LPU64" -> "LPU64"\n", res->lr_name.name[0],
+                               lvb->lvb_blocks, new->lvb_blocks);
+                        lvb->lvb_blocks = new->lvb_blocks;
+                }
         }
 
  disk_update:
@@ -248,7 +254,7 @@ static int filter_lvbo_update(struct ldlm_resource *res,
                        lvb->lvb_ctime, LTIME_S(inode->i_ctime));
                 lvb->lvb_ctime = LTIME_S(inode->i_ctime);
         }
-        if (lvb->lvb_blocks != inode->i_blocks) {
+        if (inode->i_blocks > lvb->lvb_blocks || !increase_only) {
                 CDEBUG(D_DLMTRACE,"res: "LPU64" updating lvb blocks from disk: "
                        LPU64" -> %llu\n", res->lr_name.name[0],
                        lvb->lvb_blocks, (unsigned long long)inode->i_blocks);