Whamcloud - gitweb
LU-657 test: limit the write size in run_dd
[fs/lustre-release.git] / lustre / lclient / glimpse.c
index 78acee6..5d91c75 100644 (file)
@@ -1,6 +1,4 @@
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
+/*
  * GPL HEADER START
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  * GPL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2012, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
 #include <sys/stat.h>
 #include <sys/queue.h>
 #include <fcntl.h>
-# include <sysio.h>
-# ifdef HAVE_XTIO_H
-#  include <xtio.h>
-# endif
-# include <fs.h>
-# include <mount.h>
-# include <inode.h>
-# ifdef HAVE_FILE_H
-#  include <file.h>
-# endif
-# include <liblustre.h>
+#include <liblustre.h>
 #endif
 
 #include "cl_object.h"
@@ -87,8 +77,32 @@ 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)
+                    struct inode *inode, struct cl_object *clob, int agl)
 {
         struct cl_lock_descr *descr = &ccc_env_info(env)->cti_descr;
         struct cl_inode_info *lli   = cl_i2info(inode);
@@ -101,7 +115,7 @@ int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
         result = 0;
         if (!(lli->lli_flags & LLIF_MDS_SIZE_LOCK)) {
                 CDEBUG(D_DLMTRACE, "Glimpsing inode "DFID"\n", PFID(fid));
-                if (lli->lli_smd) {
+               if (lli->lli_has_smd) {
                         /* NOTE: this looks like DLM lock request, but it may
                          *       not be one. Due to CEF_ASYNC flag (translated
                          *       to LDLM_FL_HAS_INTENT by osc), this is
@@ -118,25 +132,49 @@ int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
                         *descr = whole_file;
                         descr->cld_obj   = clob;
                         descr->cld_mode  = CLM_PHANTOM;
-                        /* The lockreq for glimpse should be mandatory,
-                         * otherwise, osc may decide to use lockless */
-                        io->ci_lockreq = CILR_MANDATORY;
+                        descr->cld_enq_flags = CEF_ASYNC | CEF_MUST;
+                        if (agl)
+                                descr->cld_enq_flags |= CEF_AGL;
                         cio->cui_glimpse = 1;
-                        lock = cl_lock_request(env, io, descr, CEF_ASYNC,
-                                               "glimpse", cfs_current());
+                        /*
+                         * CEF_ASYNC is used because glimpse sub-locks cannot
+                         * deadlock (because they never conflict with other
+                         * locks) and, hence, can be enqueued out-of-order.
+                         *
+                         * CEF_MUST protects glimpse lock from conversion into
+                         * a lockless mode.
+                         */
+                        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 (lock == NULL)
+                                RETURN(0);
+
+                        if (IS_ERR(lock))
+                                RETURN(PTR_ERR(lock));
+
+                        LASSERT(agl == 0);
+                        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");
+                       cl_merge_lvb(inode);
+                }
         }
 
         RETURN(result);
@@ -145,7 +183,6 @@ int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
 static int cl_io_get(struct inode *inode, struct lu_env **envout,
                      struct cl_io **ioout, int *refcheck)
 {
-        struct ccc_thread_info *info;
         struct lu_env          *env;
         struct cl_io           *io;
         struct cl_inode_info   *lli = cl_i2info(inode);
@@ -155,8 +192,7 @@ static int cl_io_get(struct inode *inode, struct lu_env **envout,
         if (S_ISREG(cl_inode_mode(inode))) {
                 env = cl_env_get(refcheck);
                 if (!IS_ERR(env)) {
-                        info = ccc_env_info(env);
-                        io = &info->cti_io;
+                        io = ccc_env_thread_io(env);
                         io->ci_obj = clob;
                         *envout = env;
                         *ioout  = io;
@@ -168,7 +204,7 @@ static int cl_io_get(struct inode *inode, struct lu_env **envout,
         return result;
 }
 
-int cl_glimpse_size(struct inode *inode)
+int cl_glimpse_size0(struct inode *inode, int agl)
 {
         /*
          * We don't need ast_flags argument to cl_glimpse_size(), because
@@ -180,8 +216,8 @@ int cl_glimpse_size(struct inode *inode)
          * cl_glimpse_size(), which doesn't make sense: glimpse locks are not
          * blocking anyway.
          */
-        struct lu_env          *env;
-        struct cl_io           *io;
+        struct lu_env          *env = NULL;
+        struct cl_io           *io  = NULL;
         int                     result;
         int                     refcheck;
 
@@ -189,6 +225,8 @@ int cl_glimpse_size(struct inode *inode)
 
         result = cl_io_get(inode, &env, &io, &refcheck);
         if (result > 0) {
+       again:
+               io->ci_verify_layout = 1;
                 result = cl_io_init(env, io, CIT_MISC, io->ci_obj);
                 if (result > 0)
                         /*
@@ -197,17 +235,20 @@ int cl_glimpse_size(struct inode *inode)
                          */
                         result = io->ci_result;
                 else if (result == 0)
-                        result = cl_glimpse_lock(env, io, inode, io->ci_obj);
+                        result = cl_glimpse_lock(env, io, inode, io->ci_obj,
+                                                 agl);
                 cl_io_fini(env, io);
-                cl_env_put(env, &refcheck);
-        }
-        RETURN(result);
+               if (unlikely(io->ci_need_restart))
+                       goto again;
+               cl_env_put(env, &refcheck);
+       }
+       RETURN(result);
 }
 
 int cl_local_size(struct inode *inode)
 {
-        struct lu_env           *env;
-        struct cl_io            *io;
+        struct lu_env           *env = NULL;
+        struct cl_io            *io  = NULL;
         struct ccc_thread_info  *cti;
         struct cl_object        *clob;
         struct cl_lock_descr    *descr;
@@ -217,10 +258,7 @@ int cl_local_size(struct inode *inode)
 
         ENTRY;
 
-        /*
-         * XXX layering violation.
-         */
-        if (cl_i2info(inode)->lli_smd->lsm_stripe_count == 0)
+       if (!cl_i2info(inode)->lli_has_smd)
                 RETURN(0);
 
         result = cl_io_get(inode, &env, &io, &refcheck);