Whamcloud - gitweb
land clio.
authornikita <nikita>
Fri, 7 Nov 2008 23:54:43 +0000 (23:54 +0000)
committernikita <nikita>
Fri, 7 Nov 2008 23:54:43 +0000 (23:54 +0000)
b=14166

180 files changed:
lustre/ChangeLog
lustre/autoMakefile.am
lustre/autoconf/lustre-core.m4
lustre/cmm/cmm_device.c
lustre/cmm/cmm_object.c
lustre/cmm/mdc_device.c
lustre/cmm/mdc_object.c
lustre/doc/lock-ordering [new file with mode: 0644]
lustre/fld/fld_request.c
lustre/include/Makefile.am
lustre/include/cl_object.h [new file with mode: 0644]
lustre/include/dt_object.h
lustre/include/lclient.h [new file with mode: 0644]
lustre/include/liblustre.h
lustre/include/linux/lustre_acl.h
lustre/include/linux/lustre_compat25.h
lustre/include/linux/obd_support.h
lustre/include/lu_object.h
lustre/include/lustre/lustre_idl.h
lustre/include/lustre_cache.h [deleted file]
lustre/include/lustre_dlm.h
lustre/include/lustre_lite.h
lustre/include/lustre_net.h
lustre/include/md_object.h
lustre/include/obd.h
lustre/include/obd_class.h
lustre/include/obd_ost.h
lustre/include/obd_support.h
lustre/kernel_patches/patches/2.6-rhel4-kgdb-ga.patch
lustre/kernel_patches/patches/2.6-rhel5-kgdb-ga.patch [new file with mode: 0644]
lustre/kernel_patches/patches/kgdb-2.6.18-vanilla.patch [new file with mode: 0644]
lustre/kernel_patches/patches/lockdep_chains-2.6.18-vanilla.patch [new file with mode: 0644]
lustre/kernel_patches/series/2.6-rhel4.series
lustre/kernel_patches/series/2.6.18-vanilla.series
lustre/lclient/Makefile.am [new file with mode: 0644]
lustre/lclient/glimpse.c [new file with mode: 0644]
lustre/lclient/lcommon_cl.c [new file with mode: 0644]
lustre/ldlm/ldlm_extent.c
lustre/ldlm/ldlm_flock.c
lustre/ldlm/ldlm_internal.h
lustre/ldlm/ldlm_lib.c
lustre/ldlm/ldlm_lock.c
lustre/ldlm/ldlm_lockd.c
lustre/ldlm/ldlm_pool.c
lustre/ldlm/ldlm_request.c
lustre/liblustre/Makefile.am
lustre/liblustre/dir.c
lustre/liblustre/file.c
lustre/liblustre/llite_cl.c [new file with mode: 0644]
lustre/liblustre/llite_lib.c
lustre/liblustre/llite_lib.h
lustre/liblustre/namei.c
lustre/liblustre/rw.c
lustre/liblustre/super.c
lustre/liblustre/tests/sanity.c
lustre/llite/Makefile.in
lustre/llite/autoMakefile.am
lustre/llite/dcache.c
lustre/llite/file.c
lustre/llite/llite_capa.c
lustre/llite/llite_close.c
lustre/llite/llite_internal.h
lustre/llite/llite_lib.c
lustre/llite/llite_mmap.c
lustre/llite/lloop.c
lustre/llite/lproc_llite.c
lustre/llite/namei.c
lustre/llite/rw.c
lustre/llite/rw26.c
lustre/llite/super25.c
lustre/llite/symlink.c
lustre/llite/vvp_dev.c [new file with mode: 0644]
lustre/llite/vvp_internal.h [new file with mode: 0644]
lustre/llite/vvp_io.c [new file with mode: 0644]
lustre/llite/vvp_lock.c [new file with mode: 0644]
lustre/llite/vvp_object.c [new file with mode: 0644]
lustre/llite/vvp_page.c [new file with mode: 0644]
lustre/lmv/lmv_internal.h
lustre/lmv/lmv_obd.c
lustre/lmv/lproc_lmv.c
lustre/lov/Makefile.in
lustre/lov/autoMakefile.am
lustre/lov/lov_cl_internal.h [new file with mode: 0644]
lustre/lov/lov_dev.c [new file with mode: 0644]
lustre/lov/lov_ea.c
lustre/lov/lov_internal.h
lustre/lov/lov_io.c [new file with mode: 0644]
lustre/lov/lov_lock.c [new file with mode: 0644]
lustre/lov/lov_merge.c
lustre/lov/lov_obd.c
lustre/lov/lov_object.c [new file with mode: 0644]
lustre/lov/lov_page.c [new file with mode: 0644]
lustre/lov/lov_request.c
lustre/lov/lovsub_dev.c [new file with mode: 0644]
lustre/lov/lovsub_io.c [moved from lustre/include/obd_echo.h with 58% similarity]
lustre/lov/lovsub_lock.c [new file with mode: 0644]
lustre/lov/lovsub_object.c [new file with mode: 0644]
lustre/lov/lovsub_page.c [new file with mode: 0644]
lustre/lvfs/fsfilt_ext3.c
lustre/lvfs/lvfs_linux.c
lustre/lvfs/quotafmt_test.c
lustre/mdc/mdc_locks.c
lustre/mdc/mdc_reint.c
lustre/mdc/mdc_request.c
lustre/mdd/mdd_device.c
lustre/mdd/mdd_dir.c
lustre/mdd/mdd_internal.h
lustre/mdd/mdd_lov.c
lustre/mdd/mdd_object.c
lustre/mdd/mdd_permission.c
lustre/mds/lproc_mds.c
lustre/mds/mds_fs.c
lustre/mds/mds_lov.c
lustre/mdt/mdt_capa.c
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_recovery.c
lustre/mdt/mdt_reint.c
lustre/mgs/mgs_llog.c
lustre/obdclass/Makefile.in
lustre/obdclass/autoMakefile.am
lustre/obdclass/cl_internal.h [new file with mode: 0644]
lustre/obdclass/cl_io.c [new file with mode: 0644]
lustre/obdclass/cl_lock.c [new file with mode: 0644]
lustre/obdclass/cl_object.c [new file with mode: 0644]
lustre/obdclass/cl_page.c [new file with mode: 0644]
lustre/obdclass/class_obd.c
lustre/obdclass/genops.c
lustre/obdclass/linux/linux-module.c
lustre/obdclass/linux/linux-obdo.c
lustre/obdclass/llog_cat.c
lustre/obdclass/llog_lvfs.c
lustre/obdclass/llog_obd.c
lustre/obdclass/lprocfs_status.c
lustre/obdclass/lu_object.c
lustre/obdclass/lu_time.c
lustre/obdclass/obd_mount.c
lustre/obdecho/autoMakefile.am
lustre/obdecho/echo.c
lustre/obdecho/echo_client.c
lustre/obdecho/echo_internal.h [new file with mode: 0644]
lustre/obdfilter/filter_io.c
lustre/osc/Makefile.in
lustre/osc/autoMakefile.am
lustre/osc/cache.c [deleted file]
lustre/osc/lproc_osc.c
lustre/osc/osc_cl_internal.h [new file with mode: 0644]
lustre/osc/osc_create.c
lustre/osc/osc_dev.c [new file with mode: 0644]
lustre/osc/osc_internal.h
lustre/osc/osc_io.c [new file with mode: 0644]
lustre/osc/osc_lock.c [new file with mode: 0644]
lustre/osc/osc_object.c [new file with mode: 0644]
lustre/osc/osc_page.c [new file with mode: 0644]
lustre/osc/osc_request.c
lustre/osd/osd_handler.c
lustre/osd/osd_internal.h
lustre/ptlrpc/client.c
lustre/ptlrpc/events.c
lustre/ptlrpc/import.c
lustre/ptlrpc/layout.c
lustre/ptlrpc/pack_generic.c
lustre/ptlrpc/pinger.c
lustre/ptlrpc/ptlrpcd.c
lustre/ptlrpc/recov_thread.c
lustre/ptlrpc/sec.c
lustre/ptlrpc/sec_plain.c
lustre/ptlrpc/service.c
lustre/quota/quota_context.c
lustre/tests/fsx.c
lustre/tests/it_test.c
lustre/tests/kbuild [new file with mode: 0755]
lustre/tests/lockorder.sh
lustre/tests/multifstat.c
lustre/tests/sanity-nano.sh [new file with mode: 0755]
lustre/tests/sanity.sh
lustre/tests/sanityN.sh
lustre/tests/sendfile.c
lustre/tests/test-framework.sh
lustre/utils/gss/lsupport.c
lustre/utils/obdiolib.c

index bd543fd..c7d0d77 100644 (file)
@@ -14,6 +14,10 @@ tbd  Sun Microsystems, Inc.
        * File join has been disabled in this release, refer to Bugzilla 16929.
 
 Severity   : enhancement
+Bugzilla   : 14166
+Description: New client IO stack (CLIO).
+
+Severity   : enhancement
 Bugzilla   : 15393
 Description: Commit on sharing. Eliminate inter-client dependencies between
             uncommitted transactions by doing transaction commits.
index 55aa1b6..3ad4024 100644 (file)
@@ -42,7 +42,7 @@ ALWAYS_SUBDIRS := include lvfs obdclass ldlm ptlrpc osc lov obdecho \
 
 SERVER_SUBDIRS := obdfilter ost mds mgs mdt cmm mdd osd
 
-CLIENT_SUBDIRS := mdc lmv llite
+CLIENT_SUBDIRS := mdc lmv llite lclient
 
 QUOTA_SUBDIRS := quota
 
index 4899310..2a87e8f 100644 (file)
@@ -258,9 +258,9 @@ LB_LINUX_TRY_COMPILE([
 # LC_FUNC_REGISTER_CACHE
 #
 # if register_cache() is defined by kernel
-# 
+#
 # There are two ways to shrink one customized cache in linux kernels. For the
-# kernels are prior than 2.6.5(?), register_cache() is used, and for latest 
+# kernels are prior than 2.6.5(?), register_cache() is used, and for latest
 # kernels, set_shrinker() is used instead.
 #
 AC_DEFUN([LC_FUNC_REGISTER_CACHE],
@@ -342,7 +342,7 @@ LB_LINUX_TRY_COMPILE([
         AC_MSG_RESULT([yes])
         AC_DEFINE(HAVE_DEV_SET_RDONLY, 1, [kernel has new dev_set_rdonly])
 ],[
-        AC_MSG_RESULT([no, Linux kernel source needs to be patches by lustre 
+        AC_MSG_RESULT([no, Linux kernel source needs to be patches by lustre
 kernel patches from Lustre version 1.4.3 or above.])
 ])
 ])
@@ -580,7 +580,7 @@ AC_DEFUN([LC_BIT_SPINLOCK_H],
 #
 # LC_POSIX_ACL_XATTR
 #
-# If we have xattr_acl.h 
+# If we have xattr_acl.h
 #
 AC_DEFUN([LC_XATTR_ACL],
 [LB_CHECK_FILE([$LINUX/include/linux/xattr_acl.h],[
@@ -729,7 +729,7 @@ AC_DEFUN([LC_CONFIG_SUNRPC],
 #
 AC_DEFUN([LC_CONFIG_GSS_KEYRING],
 [AC_MSG_CHECKING([whether to enable gss keyring backend])
- AC_ARG_ENABLE([gss_keyring], 
+ AC_ARG_ENABLE([gss_keyring],
               [AC_HELP_STRING([--disable-gss-keyring],
                                [disable gss keyring backend])],
               [],[enable_gss_keyring='yes'])
@@ -757,7 +757,7 @@ m4_pattern_allow(AC_KERBEROS_V5)
 #
 AC_DEFUN([LC_CONFIG_GSS],
 [AC_MSG_CHECKING([whether to enable gss/krb5 support])
- AC_ARG_ENABLE([gss], 
+ AC_ARG_ENABLE([gss],
                [AC_HELP_STRING([--enable-gss], [enable gss/krb5 support])],
                [],[enable_gss='no'])
  AC_MSG_RESULT([$enable_gss])
@@ -949,7 +949,7 @@ LB_LINUX_TRY_COMPILE([
         AC_MSG_RESULT(no)
 ])
 ])
+
 #
 # LC_STATFS_DENTRY_PARAM
 # starting from 2.6.18 linux kernel uses dentry instead of
@@ -990,7 +990,7 @@ LB_LINUX_TRY_COMPILE([
 ])
 ])
 
-# 
+#
 # LC_INVALIDATEPAGE_RETURN_INT
 # more 2.6 api changes.  return type for the invalidatepage
 # address_space_operation is 'void' in new kernels but 'int' in old
@@ -1048,7 +1048,7 @@ LB_LINUX_TRY_COMPILE([
 #include <linux/fs.h>
 ],[
        struct inode i;
-       i.i_blksize = 0; 
+       i.i_blksize = 0;
 ],[
        AC_MSG_RESULT(yes)
        AC_DEFINE(HAVE_INODE_BLKSIZE, 1,
@@ -1086,37 +1086,37 @@ LB_LINUX_TRY_COMPILE([
 EXTRA_KCFLAGS="$tmp_flags"
 ])
 
-# LC_GENERIC_FILE_WRITE
-# 2.6.19 introduce do_sync_write instead of
-# generic_file_write
-AC_DEFUN([LC_GENERIC_FILE_WRITE],
-[AC_MSG_CHECKING([use generic_file_write])
+# LC_FILE_WRITEV
+# 2.6.19 replaced writev with aio_write
+AC_DEFUN([LC_FILE_WRITEV],
+[AC_MSG_CHECKING([writev in fops])
 LB_LINUX_TRY_COMPILE([
         #include <linux/fs.h>
 ],[
-        int result = generic_file_read(NULL, NULL, 0, 0);
+        struct file_operations *fops;
+        fops->writev = NULL;
 ],[
         AC_MSG_RESULT(yes)
-        AC_DEFINE(HAVE_GENERIC_FILE_WRITE, 1,
-                [use generic_file_write])
+        AC_DEFINE(HAVE_FILE_WRITEV, 1,
+                [use fops->writev])
 ],[
        AC_MSG_RESULT(no)
 ])
 ])
 
 # LC_GENERIC_FILE_READ
-# 2.6.19 need to use do_sync_read instead of
-# generic_file_read
-AC_DEFUN([LC_GENERIC_FILE_READ],
-[AC_MSG_CHECKING([use generic_file_read])
+# 2.6.19 replaced readv with aio_read
+AC_DEFUN([LC_FILE_READV],
+[AC_MSG_CHECKING([readv in fops])
 LB_LINUX_TRY_COMPILE([
         #include <linux/fs.h>
 ],[
-        int result = generic_file_read(NULL, NULL, 0, 0);
+        struct file_operations *fops;
+        fops->readv = NULL;
 ],[
         AC_MSG_RESULT(yes)
-        AC_DEFINE(HAVE_GENERIC_FILE_READ, 1,
-                [use generic_file_read])
+        AC_DEFINE(HAVE_FILE_READV, 1,
+                [use fops->readv])
 ],[
         AC_MSG_RESULT(no)
 ])
@@ -1140,7 +1140,7 @@ LB_LINUX_TRY_COMPILE([
 ])
 
 # LC_CANCEL_DIRTY_PAGE
-# 2.6.20 introduse cancel_dirty_page instead of 
+# 2.6.20 introduse cancel_dirty_page instead of
 # clear_page_dirty.
 AC_DEFUN([LC_CANCEL_DIRTY_PAGE],
 [AC_MSG_CHECKING([kernel has cancel_dirty_page])
@@ -1348,7 +1348,7 @@ LB_LINUX_TRY_COMPILE([
         int i = unregister_blkdev(0,NULL);
 ],[
         AC_MSG_RESULT([yes])
-        AC_DEFINE(HAVE_UNREGISTER_BLKDEV_RETURN_INT, 1, 
+        AC_DEFINE(HAVE_UNREGISTER_BLKDEV_RETURN_INT, 1,
                 [unregister_blkdev return int])
 ],[
         AC_MSG_RESULT([no])
@@ -1467,7 +1467,7 @@ AC_TRY_RUN([
 #include <linux/autoconf.h>
 #include <linux/types.h>
 #undef __KERNEL__
-// block include 
+// block include
 #define __LINUX_POSIX_ACL_H
 
 # ifdef CONFIG_FS_POSIX_ACL
@@ -1504,7 +1504,7 @@ CFLAGS="$tmp_flags"
 ])
 
 #
-# check for crypto API 
+# check for crypto API
 #
 AC_DEFUN([LC_ASYNC_BLOCK_CIPHER],
 [AC_MSG_CHECKING([if kernel has block cipher support])
@@ -1637,15 +1637,15 @@ AC_DEFUN([LC_PROG_LINUX],
          # 2.6.19
          LC_INODE_BLKSIZE
          LC_VFS_READDIR_U64_INO
-         LC_GENERIC_FILE_READ
-         LC_GENERIC_FILE_WRITE
+         LC_FILE_WRITEV
+         LC_FILE_READV
 
          # 2.6.20
          LC_CANCEL_DIRTY_PAGE
 
          # raid5-zerocopy patch
          LC_PAGE_CONSTANT
-                 
+               
         # 2.6.22
          LC_INVALIDATE_BDEV_2ARG
          LC_ASYNC_BLOCK_CIPHER
@@ -1765,7 +1765,7 @@ LC_CONFIG_LIBLUSTRE_RECOVERY
 
 AC_DEFUN([LC_CONFIG_LRU_RESIZE],
 [AC_MSG_CHECKING([whether to enable lru self-adjusting])
-AC_ARG_ENABLE([lru_resize], 
+AC_ARG_ENABLE([lru_resize],
        AC_HELP_STRING([--enable-lru-resize],
                        [enable lru resize support]),
        [],[enable_lru_resize='yes'])
@@ -1781,7 +1781,7 @@ fi
 # whether to enable quota support
 #
 AC_DEFUN([LC_CONFIG_QUOTA],
-[AC_ARG_ENABLE([quota], 
+[AC_ARG_ENABLE([quota],
        AC_HELP_STRING([--enable-quota],
                        [enable quota support]),
        [],[enable_quota='default'])
@@ -1814,7 +1814,7 @@ fi
 #
 AC_DEFUN([LC_CONFIG_SPLIT],
 [AC_MSG_CHECKING([whether to enable split support])
-AC_ARG_ENABLE([split], 
+AC_ARG_ENABLE([split],
        AC_HELP_STRING([--enable-split],
                        [enable split support]),
        [],[enable_split='no'])
@@ -1823,7 +1823,7 @@ if test x$enable_split != xno; then
    AC_DEFINE(HAVE_SPLIT_SUPPORT, 1, [enable split support])
 fi
 ])
+
 AC_DEFUN([LC_QUOTA_READ],
 [AC_MSG_CHECKING([if kernel supports quota_read])
 LB_LINUX_TRY_COMPILE([
@@ -1866,7 +1866,7 @@ LB_LINUX_TRY_COMPILE([
 #
 # LC_FUNC_RCU
 #
-# kernels prior than 2.6.0(?) have no RCU supported; in kernel 2.6.5(SUSE), 
+# kernels prior than 2.6.0(?) have no RCU supported; in kernel 2.6.5(SUSE),
 # call_rcu takes three parameters.
 #
 AC_DEFUN([LC_FUNC_RCU],
@@ -1887,7 +1887,7 @@ LB_LINUX_TRY_COMPILE([
                 AC_DEFINE(HAVE_CALL_RCU_PARAM, 1, [call_rcu takes three parameters])
                 AC_MSG_RESULT([yes])
         ],[
-                AC_MSG_RESULT([no]) 
+                AC_MSG_RESULT([no])
         ])
 ],[
         AC_MSG_RESULT([no])
@@ -1895,7 +1895,7 @@ LB_LINUX_TRY_COMPILE([
 ])
 
 # LC_SECURITY_PLUG  # for SLES10 SP2
-# check security plug in sles10 sp2 kernel 
+# check security plug in sles10 sp2 kernel
 AC_DEFUN([LC_SECURITY_PLUG],
 [AC_MSG_CHECKING([If kernel has security plug support])
 LB_LINUX_TRY_COMPILE([
@@ -2085,6 +2085,7 @@ lustre/liblustre/Makefile
 lustre/liblustre/tests/Makefile
 lustre/llite/Makefile
 lustre/llite/autoMakefile
+lustre/lclient/Makefile
 lustre/lov/Makefile
 lustre/lov/autoMakefile
 lustre/lvfs/Makefile
index 4308533..d2c435d 100644 (file)
@@ -401,7 +401,7 @@ static struct lu_device *cmm_device_alloc(const struct lu_env *env,
                 if (!m->cmm_fld) {
                         cmm_device_free(env, l);
                         l = ERR_PTR(-ENOMEM);
-        }
+                }
         }
         RETURN(l);
 }
@@ -448,14 +448,14 @@ static int cmm_device_init(const struct lu_env *env, struct lu_device *d,
         ls = cmm2lu_dev(m)->ld_site;
         lu_site2md(ls)->ms_client_fld = m->cmm_fld;
         err = cmm_procfs_init(m, name);
-        
+
         RETURN(err);
 }
 
 static struct lu_device *cmm_device_fini(const struct lu_env *env,
                                          struct lu_device *ld)
 {
-       struct cmm_device *cm = lu2cmm_dev(ld);
+        struct cmm_device *cm = lu2cmm_dev(ld);
         struct mdc_device *mc, *tmp;
         struct lu_site *ls;
         ENTRY;
index 2289be3..3309687 100644 (file)
@@ -116,8 +116,8 @@ struct lu_object *cmm_object_alloc(const struct lu_env *env,
                 struct cml_object *clo;
 
                 OBD_ALLOC_PTR(clo);
-               if (clo != NULL) {
-                       lo = &clo->cmm_obj.cmo_obj.mo_lu;
+                if (clo != NULL) {
+                        lo = &clo->cmm_obj.cmo_obj.mo_lu;
                         lu_object_init(lo, NULL, ld);
                         clo->cmm_obj.cmo_obj.mo_ops = &cml_mo_ops;
                         clo->cmm_obj.cmo_obj.mo_dir_ops = &cml_dir_ops;
@@ -127,8 +127,8 @@ struct lu_object *cmm_object_alloc(const struct lu_env *env,
                 struct cmr_object *cro;
 
                 OBD_ALLOC_PTR(cro);
-               if (cro != NULL) {
-                       lo = &cro->cmm_obj.cmo_obj.mo_lu;
+                if (cro != NULL) {
+                        lo = &cro->cmm_obj.cmo_obj.mo_lu;
                         lu_object_init(lo, NULL, ld);
                         cro->cmm_obj.cmo_obj.mo_ops = &cmr_mo_ops;
                         cro->cmm_obj.cmo_obj.mo_dir_ops = &cmr_dir_ops;
@@ -199,9 +199,9 @@ static int cml_object_print(const struct lu_env *env, void *cookie,
 }
 
 static const struct lu_object_operations cml_obj_ops = {
-       .loo_object_init    = cml_object_init,
-       .loo_object_free    = cml_object_free,
-       .loo_object_print   = cml_object_print
+        .loo_object_init    = cml_object_init,
+        .loo_object_free    = cml_object_free,
+        .loo_object_print   = cml_object_print
 };
 
 /* CMM local md_object operations */
@@ -831,9 +831,9 @@ static int cmr_object_print(const struct lu_env *env, void *cookie,
 }
 
 static const struct lu_object_operations cmr_obj_ops = {
-       .loo_object_init    = cmr_object_init,
-       .loo_object_free    = cmr_object_free,
-       .loo_object_print   = cmr_object_print
+        .loo_object_init    = cmr_object_init,
+        .loo_object_free    = cmr_object_free,
+        .loo_object_print   = cmr_object_print
 };
 
 /* CMM remote md_object operations. All are invalid */
index 8c75a6c..5507962 100644 (file)
@@ -89,7 +89,7 @@ static int mdc_obd_update(struct obd_device *host,
                 CDEBUG(D_INFO, "Update connect_flags: "LPX64"\n",
                        conn_data->ocd_connect_flags);
         }
-        
+
         RETURN(rc);
 }
 /* MDC OBD is set up already and connected to the proper MDS
@@ -146,9 +146,9 @@ static int mdc_obd_add(const struct lu_env *env,
                 ocd->ocd_ibits_known = MDS_INODELOCK_UPDATE;
                 ocd->ocd_connect_flags = OBD_CONNECT_VERSION |
                                          OBD_CONNECT_ACL |
-                                         OBD_CONNECT_LCL_CLIENT | 
+                                         OBD_CONNECT_LCL_CLIENT |
                                          OBD_CONNECT_MDS_CAPA |
-                                         OBD_CONNECT_OSS_CAPA | 
+                                         OBD_CONNECT_OSS_CAPA |
                                          OBD_CONNECT_IBITS |
                                          OBD_CONNECT_MDS_MDS |
                                          OBD_CONNECT_FID |
@@ -173,7 +173,7 @@ static int mdc_obd_add(const struct lu_env *env,
                                 mdc->obd_upcall.onu_upcall = mdc_obd_update;
                         }
                 }
-                
+
                 if (rc) {
                         obd_disconnect(desc->cl_exp);
                         desc->cl_exp = NULL;
@@ -205,7 +205,7 @@ static int mdc_obd_del(const struct lu_env *env, struct mdc_device *mc,
                 mdc_obd->obd_force = mdt_obd->obd_force;
                 mdc_obd->obd_fail = 0;
         }
-        
+
         rc = obd_fid_fini(desc->cl_exp);
         if (rc)
                 CERROR("Fid fini error %d\n", rc);
@@ -246,7 +246,7 @@ static int mdc_process_config(const struct lu_env *env,
 }
 
 static const struct lu_device_operations mdc_lu_ops = {
-       .ldo_object_alloc   = mdc_object_alloc,
+        .ldo_object_alloc   = mdc_object_alloc,
         .ldo_process_config = mdc_process_config
 };
 
@@ -254,12 +254,12 @@ void cmm_mdc_init_ea_size(const struct lu_env *env, struct mdc_device *mc,
                       int max_mdsize, int max_cookiesize)
 {
         struct obd_device *obd = class_exp2obd(mc->mc_desc.cl_exp);
-       
+
         obd->u.cli.cl_max_mds_easize = max_mdsize;
         obd->u.cli.cl_max_mds_cookiesize = max_cookiesize;
 }
 
-static int mdc_device_init(const struct lu_env *env, struct lu_device *ld, 
+static int mdc_device_init(const struct lu_env *env, struct lu_device *ld,
                            const char *name, struct lu_device *next)
 {
         return 0;
@@ -286,10 +286,9 @@ static struct lu_device *mdc_device_alloc(const struct lu_env *env,
         } else {
                 md_device_init(&mc->mc_md_dev, ldt);
                 mc->mc_md_dev.md_ops = &mdc_md_ops;
-               ld = mdc2lu_dev(mc);
+                ld = mdc2lu_dev(mc);
                 ld->ld_ops = &mdc_lu_ops;
                 sema_init(&mc->mc_fid_sem, 1);
-
         }
 
         RETURN (ld);
@@ -300,7 +299,7 @@ static struct lu_device *mdc_device_free(const struct lu_env *env,
 {
         struct mdc_device *mc = lu2mdc_dev(ld);
 
-       LASSERTF(atomic_read(&ld->ld_ref) == 0,
+        LASSERTF(atomic_read(&ld->ld_ref) == 0,
                  "Refcount = %i\n", atomic_read(&ld->ld_ref));
         LASSERT(list_empty(&mc->mc_linkage));
         md_device_fini(&mc->mc_md_dev);
index 36c7678..2e884ba 100644 (file)
@@ -176,7 +176,7 @@ static int mdc_req2attr_update(const struct lu_env *env,
                 LASSERT(ma->ma_capa != NULL);
                 *ma->ma_capa = *capa;
         }
-                
+
         if ((body->valid & OBD_MD_FLEASIZE) || (body->valid & OBD_MD_FLDIREA)) {
                 if (body->eadatasize == 0) {
                         CERROR("No size defined for easize field\n");
@@ -189,7 +189,7 @@ static int mdc_req2attr_update(const struct lu_env *env,
                         RETURN(-EPROTO);
 
                 LASSERT(ma->ma_lmm != NULL);
-                LASSERT(ma->ma_lmm_size >= body->eadatasize); 
+                LASSERT(ma->ma_lmm_size >= body->eadatasize);
                 ma->ma_lmm_size = body->eadatasize;
                 memcpy(ma->ma_lmm, md, ma->ma_lmm_size);
                 ma->ma_valid |= MA_LOV;
@@ -207,7 +207,7 @@ static int mdc_req2attr_update(const struct lu_env *env,
                         RETURN(-EPROTO);
                 }
 
-                cookie = req_capsule_server_sized_get(&req->rq_pill, 
+                cookie = req_capsule_server_sized_get(&req->rq_pill,
                                                       &RMF_LOGCOOKIES,
                                                       body->aclsize);
                 if (cookie == NULL)
@@ -226,7 +226,7 @@ static int mdc_req2attr_update(const struct lu_env *env,
                         RETURN(-EPROTO);
                 }
 
-                acl = req_capsule_server_sized_get(&req->rq_pill, 
+                acl = req_capsule_server_sized_get(&req->rq_pill,
                                                    &RMF_ACL,
                                                    body->aclsize);
                 if (acl == NULL)
@@ -349,7 +349,7 @@ static int mdc_object_create(const struct lu_env *env,
         mci = mdc_info_init(env);
         mci->mci_opdata.op_bias = MDS_CROSS_REF;
         mci->mci_opdata.op_fid2 = *lu_object_fid(&mo->mo_lu);
-        
+
         /* Parent fid is needed to create dotdot on the remote node. */
         mci->mci_opdata.op_fid1 = *(spec->u.sp_pfid);
         mci->mci_opdata.op_mod_time = la->la_ctime;
@@ -572,7 +572,7 @@ static int mdc_rename_tgt(const struct lu_env *env, struct md_object *mo_p,
 
         RETURN(rc);
 }
-/* 
+/*
  * Return resulting fid in sfid
  * 0: fids are not relatives
  * fid: fid at which search stopped
@@ -594,7 +594,7 @@ static int mdc_is_subdir(const struct lu_env *env, struct md_object *mo,
                 body = req_capsule_server_get(&mci->mci_req->rq_pill,
                                               &RMF_MDT_BODY);
                 LASSERT(body->valid & OBD_MD_FLID);
-        
+
                 CDEBUG(D_INFO, "Remote mdo_is_subdir(), new src "DFID"\n",
                        PFID(&body->fid1));
                 *sfid = body->fid1;
diff --git a/lustre/doc/lock-ordering b/lustre/doc/lock-ordering
new file mode 100644 (file)
index 0000000..3bea748
--- /dev/null
@@ -0,0 +1,309 @@
+/* this is dot(1) input file for lock-ordering diagram */
+/* it should be passed through C preprocessor first */
+/* cpp -P -DFITPAGE lock-ordering | tred | dot -Tps | gv -media a4 - */
+
+/*
+sb->s_umount
+    libcfs_nidstring_lock
+    obd_dev_lock
+    g_uuid_lock
+    obd_types_lock
+    type->obd_type_lock
+    obd->obd_dev_lock
+    handle_base_lock
+    bucket->lock
+    _lprocfs_lock
+    the_lnet.ln_lock
+        request->rq_lock
+    ptlrpc_all_services_lock
+    service->srv_lock
+    shrinker_rwsem
+    conn_lock
+        hash_body->lchb_hash_tables[i].lhb_lock
+    hash_body->lchb_hash_tables[i].lhb_lock
+    imp->imp_lock
+    olg->olg_lock
+    cli->cl_sem
+        handle_base_lock
+        bucket->lock
+        obd->obd_dev_lock
+            ref->lf_guard
+            hash_body->lchb_hash_tables[i].lhb_lock
+        h->h_lock
+        _lprocfs_lock
+        imp->imp_lock
+            h->h_lock
+        policy_lock
+        null_sec.ps_lock
+        ptlrpc_last_xid_lock
+        set->set_new_req_lock
+    h->h_lock
+    ns->ns_hash_lock
+    ns->ns_unused_lock
+    lock->l_lock
+    null_sec.ps_lock
+    ptlrpc_last_xid_lock
+    request->rq_lock
+    ksocknal_data.ksnd_global_lock
+    at->at_lock
+    fld->lcf_lock
+    obd->obd_pool_lock
+    obd->obd_osfs_lock
+    lov->lov_qos.lq_rw_sem
+    sbi->ll_lco.lco_lock
+    cache->fci_lock
+    inode_lock
+    dcache_lock
+        dentry->d_lock
+slock-AF_INET/1
+    ksocknal_data.ksnd_global_lock
+        ksocknal_data.ksnd_connd_lock
+        kss->kss_lock
+pl->pl_lock
+    obd->obd_pool_lock
+inode->i_mutex
+    ns->ns_unused_lock
+    ns->ns_hash_lock
+    imp->imp_lock
+    null_sec.ps_lock
+    ptlrpc_last_xid_lock
+    bucket->lock
+    lock->l_lock
+        res->lr_lock
+            ns->ns_unused_lock
+            bucket->lock
+                h->h_lock
+            res->lr_lock/1
+            inode_lock
+            osc_ast_guard_class
+                ref->lf_guard
+    ksocknal_data.ksnd_global_lock
+    at->at_lock
+    h->h_lock
+    blp->blp_lock
+    cache->fci_lock
+    obd->obd_pool_lock
+    fld->lcf_lock
+    pl->pl_lock
+    lu_site_guard_class
+    files_lock
+lov->lo_type_guard
+    h->coh_lock_guard
+    ref->lf_guard
+    cl_lock_guard_class
+        ref->lf_guard
+        cl_lock_guard_class#2
+            cl_lock_guard_class#2
+            ref->lf_guard
+            ns->ns_hash_lock
+            ns->ns_unused_lock
+            imp->imp_lock
+            null_sec.ps_lock
+            ptlrpc_last_xid_lock
+            handle_base_lock
+            bucket->lock
+            lock->l_lock
+            set->set_new_req_lock
+            h->h_lock
+        h->coh_lock_guard
+        h->coh_page_guard
+
+*/
+#define CATTR fontsize=8 /*, fontname=Helvetica */
+#define NATTR CATTR
+#define EATTR CATTR
+
+#define SYSATTR color=yellow, style=filled
+#define PSEUDOATTR color=pink, style=filled, peripheries=2
+
+#define BLOCKATTR shape=ellipse
+#define SPINATTR shape=box
+
+#define CONDATTR color=blue, peripheries=2, BLOCKATTR
+
+#define MARKBLOCK(name) /* name -> schedulable [style=invis, weight=0] */
+
+#define SBLOCK(name, l) name [label=l, NATTR, BLOCKATTR, SYSATTR]; MARKBLOCK(name)
+
+#define SPSEUDO(name) name [NATTR, BLOCKATTR, PSEUDOATTR]; MARKBLOCK(name)
+
+#define LBLOCK(name, l) name [label=l, NATTR, BLOCKATTR]; MARKBLOCK(name)
+
+#define RCOND(name, l) name [label=l, NATTR, CONDATTR]; MARKBLOCK(name)
+
+#define MARKSPIN(name) /* schedulable -> name [style=invis, weight=0] */
+
+#define SSPIN(name, l) name [label=l, NATTR, SYSATTR, SPINATTR]; MARKSPIN(name)
+#define LSPIN(name, l) name [label=l, NATTR, SPINATTR]; MARKSPIN(name)
+
+#define ARC(from, to, func, ...) from -> to [EATTR, label=func, ## __VA_ARGS__]
+
+digraph locks {
+
+    subgraph blocking {
+        SBLOCK(sb__s_umount, "sb->s_umount")
+        LBLOCK(_lprocfs_lock, "_lprocfs_lock")
+        LBLOCK(cli__cl_sem, "cli->cl_sem")
+        SBLOCK(shrinker_rwsem, "shrinker_rwsem")
+        LBLOCK(lov__lov_qos_lq_rw_sem, "lov->lov_qos.lq_rw_sem")
+        SBLOCK(inode__i_mutex, "inode->i_mutex")
+        LBLOCK(lov__lo_type_guard, "lov->lo_type_guard")
+        LBLOCK(cl_lock_guard_class, "cl_lock_guard_class")
+    }
+
+    subgraph spin {
+        LSPIN(h__coh_lock_guard, "h->coh_lock_guard")
+        LSPIN(h__coh_page_guard, "h->coh_page_guard")
+        LSPIN(libcfs_nidstring_lock, "libcfs_nidstring_lock")
+        LSPIN(obd_dev_lock, "obd_dev_lock")
+        LSPIN(g_uuid_lock, "g_uuid_lock")
+        LSPIN(obd_types_lock, "obd_types_lock")
+        LSPIN(obd_type__obd_type_lock, "obd_type->obd_type_lock")
+        LSPIN(obd__obd_dev_lock, "obd->obd_dev_lock")
+        LSPIN(handle_base_lock, "handle_base_lock")
+        LSPIN(bucket__lock, "bucket->lock")
+        LSPIN(the_lnet_ln_lock, "the_lnet.ln_lock")
+        LSPIN(request__rq_lock, "request->rq_lock")
+        LSPIN(hash_body__lchb_hash_tables_i__lhb_lock, "hash_body->lchb_hash_tables[i].lhb_lock")
+        LSPIN(imp__imp_lock, "imp->imp_lock")
+        LSPIN(ref__lf_guard, "ref->lf_guard")
+        LSPIN(h__h_lock, "h->h_lock")
+        LSPIN(null_sec_ps_lock, "null_sec.ps_lock")
+        LSPIN(set__set_new_req_lock, "set->set_new_req_lock")
+        LSPIN(ns__ns_hash_lock, "ns->ns_hash_lock")
+        LSPIN(ns__ns_unused_lock, "ns->ns_unused_lock")
+        LSPIN(lock__l_lock, "lock->l_lock")
+        LSPIN(ksocknal_data_ksnd_global_lock, "ksocknal_data.ksnd_global_lock")
+        LSPIN(at__at_lock, "at->at_lock")
+        LSPIN(fld__lcf_lock, "fld->lcf_lock")
+        LSPIN(obd__obd_pool_lock, "obd->obd_pool_lock")
+        LSPIN(service__srv_lock, "service->srv_lock")
+        LSPIN(obd__obd_osfs_lock, "obd->obd_osfs_lock")
+        LSPIN(sbi__ll_lco_lco_lock, "sbi->ll_lco.lco_lock")
+        LSPIN(cache__fci_lock, "cache->fci_lock")
+        SSPIN(inode_lock, "inode_lock")
+        SSPIN(dcache_lock, "dcache_lock")
+        SSPIN(dentry__d_lock, "dentry->d_lock")
+        LSPIN(ksocknal_data_ksnd_connd_lock, "ksocknal_data.ksnd_connd_lock")
+        LSPIN(kss__kss_lock, "kss->kss_lock")
+        LSPIN(pl__pl_lock, "pl->pl_lock")
+        LSPIN(osc_ast_guard_class, "osc_ast_guard_class")
+        LSPIN(blp__blp_lock, "blp->blp_lock")
+        LSPIN(lu_site_guard_class, "lu_site_guard_class")
+        SSPIN(files_lock, "files_lock")
+        LSPIN(ptlrpc_all_services_lock, "ptlrpc_all_services_lock")
+        LSPIN(conn_lock, "conn_lock")
+        LSPIN(olg__olg_lock, "olg->olg_lock")
+        LSPIN(policy_lock, "policy_lock")
+        LSPIN(ptlrpc_last_xid_lock, "ptlrpc_last_xid_lock")
+    }
+
+ARC(sb__s_umount, libcfs_nidstring_lock, "")
+ARC(sb__s_umount, obd_dev_lock, "")
+ARC(sb__s_umount, g_uuid_lock, "")
+ARC(sb__s_umount, obd_types_lock, "")
+ARC(sb__s_umount, type__obd_type_lock, "")
+ARC(sb__s_umount, obd__obd_dev_lock, "")
+ARC(sb__s_umount, handle_base_lock, "")
+ARC(sb__s_umount, bucket__lock, "")
+ARC(sb__s_umount, _lprocfs_lock, "")
+ARC(sb__s_umount, the_lnet_ln_lock, "")
+ARC(sb__s_umount, ptlrpc_all_services_lock, "")
+ARC(sb__s_umount, service__srv_lock, "")
+ARC(sb__s_umount, shrinker_rwsem, "")
+ARC(sb__s_umount, conn_lock, "")
+ARC(sb__s_umount, hash_body__lchb_hash_tables_i__lhb_lock, "")
+ARC(sb__s_umount, imp__imp_lock, "")
+ARC(sb__s_umount, olg__olg_lock, "")
+ARC(sb__s_umount, cli__cl_sem, "")
+ARC(sb__s_umount, h__h_lock, "")
+ARC(sb__s_umount, ns__ns_hash_lock, "")
+ARC(sb__s_umount, ns__ns_unused_lock, "")
+ARC(sb__s_umount, lock__l_lock, "")
+ARC(sb__s_umount, null_sec_ps_lock, "")
+ARC(sb__s_umount, ptlrpc_last_xid_lock, "")
+ARC(sb__s_umount, request__rq_lock, "")
+ARC(sb__s_umount, ksocknal_data_ksnd_global_lock, "")
+ARC(sb__s_umount, at__at_lock, "")
+ARC(sb__s_umount, fld__lcf_lock, "")
+ARC(sb__s_umount, obd__obd_pool_lock, "")
+ARC(sb__s_umount, obd__obd_osfs_lock, "")
+ARC(sb__s_umount, lov__lov_qos_lq_rw_sem, "")
+ARC(sb__s_umount, sbi__ll_lco_lco_lock, "")
+ARC(sb__s_umount, cache__fci_lock, "")
+ARC(sb__s_umount, inode_lock, "")
+ARC(sb__s_umount, dcache_lock, "")
+
+ARC(the_lnet_ln_lock, request__rq_lock, "")
+ARC(conn_lock, hash_body__lchb_hash_tables_i__lhb_lock, "")
+ARC(cli__cl_sem, handle_base_lock, "")
+ARC(cli__cl_sem, bucket__lock, "")
+ARC(cli__cl_sem, obd__obd_dev_lock, "")
+ARC(cli__cl_sem, h__h_lock, "")
+ARC(cli__cl_sem, _lprocfs_lock, "")
+ARC(cli__cl_sem, imp__imp_lock, "")
+ARC(cli__cl_sem, policy_lock, "")
+ARC(cli__cl_sem, null_sec_ps_lock, "")
+ARC(cli__cl_sem, ptlrpc_last_xid_lock, "")
+ARC(cli__cl_sem, set__set_new_req_lock, "")
+
+ARC(obd__obd_dev_lock, ref__lf_guard, "")
+ARC(obd__obd_dev_lock, hash_body__lchb_hash_tables_i__lhb_lock, "")
+ARC(imp__imp_lock, h__h_lock, "")
+
+ARC(dcache_lock, dentry__d_lock, "")
+
+ARC(ksocknal_data_ksnd_global_lock, ksocknal_data_ksnd_connd_lock, "")
+ARC(ksocknal_data_ksnd_global_lock, kss__kss_lock, "")
+ARC(pl__pl_lock, obd__obd_pool_lock, "")
+
+ARC(inode__i_mutex, ns__ns_unused_lock, "")
+ARC(inode__i_mutex, ns__ns_hash_lock, "")
+ARC(inode__i_mutex, imp__imp_lock, "")
+ARC(inode__i_mutex, null_sec_ps_lock, "")
+ARC(inode__i_mutex, ptlrpc_last_xid_lock, "")
+ARC(inode__i_mutex, bucket__lock, "")
+ARC(inode__i_mutex, lock__l_lock, "")
+ARC(inode__i_mutex, ksocknal_data_ksnd_global_lock, "")
+ARC(inode__i_mutex, at__at_lock, "")
+ARC(inode__i_mutex, h__h_lock, "")
+ARC(inode__i_mutex, blp__blp_lock, "")
+ARC(inode__i_mutex, cache__fci_lock, "")
+ARC(inode__i_mutex, obd__obd_pool_lock, "")
+ARC(inode__i_mutex, fld__lcf_lock, "")
+ARC(inode__i_mutex, pl__pl_lock, "")
+ARC(inode__i_mutex, lu_site_guard_class, "")
+ARC(inode__i_mutex, files_lock, "")
+
+ARC(lock__l_lock, res__lr_lock, "")
+ARC(res__lr_lock, ns__ns_unused_lock, "")
+ARC(res__lr_lock, bucket__lock, "")
+ARC(res__lr_lock, res__lr_lock, "")
+ARC(res__lr_lock, inode_lock, "")
+ARC(res__lr_lock, osc_ast_guard_class, "")
+
+ARC(osc_ast_guard_class, ref__lf_guard, "")
+ARC(bucket__lock, h__h_lock, "")
+
+ARC(cl_lock_guard_class, cl_lock_guard_class, "")
+ARC(cl_lock_guard_class, ref__lf_guard, "")
+ARC(cl_lock_guard_class, ns__ns_hash_lock, "")
+ARC(cl_lock_guard_class, ns__ns_unused_lock, "")
+ARC(cl_lock_guard_class, imp__imp_lock, "")
+ARC(cl_lock_guard_class, null_sec_ps_lock, "")
+ARC(cl_lock_guard_class, ptlrpc_last_xid_lock, "")
+ARC(cl_lock_guard_class, handle_base_lock, "")
+ARC(cl_lock_guard_class, bucket__lock, "")
+ARC(cl_lock_guard_class, lock__l_lock, "")
+ARC(cl_lock_guard_class, set__set_new_req_lock, "")
+ARC(cl_lock_guard_class, h__h_lock, "")
+ARC(cl_lock_guard_class, ref__lf_guard, "")
+ARC(cl_lock_guard_class, cl_lock_guard_class, "")
+ARC(cl_lock_guard_class, h__coh_lock_guard, "")
+ARC(cl_lock_guard_class, h__coh_page_guard, "")
+
+ARC(lov__lo_type_guard, h__coh_lock_guard, "")
+ARC(lov__lo_type_guard, ref__lf_guard, "")
+ARC(lov__lo_type_guard, cl_lock_guard_class, "")
+
+}
index cdb5110..39fb13b 100644 (file)
@@ -68,7 +68,7 @@
 #include <lustre_mdc.h>
 #include "fld_internal.h"
 
-/* TODO: these 3 functions are copies of flow-control code from mdc_lib.c 
+/* TODO: these 3 functions are copies of flow-control code from mdc_lib.c
  * It should be common thing. The same about mdc RPC lock */
 static int fld_req_avail(struct client_obd *cli, struct mdc_cache_waiter *mcw)
 {
@@ -105,7 +105,7 @@ static void fld_exit_request(struct client_obd *cli)
         spin_lock(&cli->cl_loi_list_lock);
         cli->cl_r_in_flight--;
         list_for_each_safe(l, tmp, &cli->cl_cache_waiters) {
-                
+
                 if (cli->cl_r_in_flight >= cli->cl_max_rpcs_in_flight) {
                         /* No free request slots anymore */
                         break;
@@ -606,7 +606,7 @@ int fld_client_lookup(struct lu_client_fld *fld,
                 /*
                  * insert the 'inflight' sequence. No need to protect that,
                  * we are trying to reduce numbers of RPC but not restrict
-                 * to them exactly one 
+                 * to them exactly one
                  */
                 fld_cache_insert_inflight(fld->lcf_cache, seq);
                 rc = fld_client_rpc(target->ft_exp,
@@ -619,7 +619,7 @@ int fld_client_lookup(struct lu_client_fld *fld,
                  * The current solution for IGIF is to bind it to mds0.
                  * In the future, this should be fixed once IGIF can be found
                  * in FLD.
-                 */ 
+                 */
                 md_fld.mf_mds = 0;
                 rc = 0;
         }
index 9803237..d18e1a9 100644 (file)
@@ -41,9 +41,9 @@ EXTRA_DIST = ioctl.h liblustre.h lprocfs_status.h lustre_cfg.h        \
              lustre_fsfilt.h lustre_ha.h lustre_handles.h lustre_import.h \
              lustre_lib.h lustre_sec.h lustre_lite.h lustre_log.h lustre_mds.h \
              lustre_mdc.h lustre_net.h lustre_quota.h lustre_ucache.h lvfs.h \
-             class_hash.h obd_cache.h obd_class.h obd_echo.h obd.h obd_lov.h \
+             class_hash.h obd_cache.h obd_class.h obd.h obd_lov.h \
             obd_ost.h obd_support.h lustre_ver.h lu_object.h lu_time.h  \
              md_object.h dt_object.h lustre_param.h lustre_mdt.h \
              lustre_fid.h lustre_fld.h lustre_req_layout.h lustre_capa.h \
              lustre_idmap.h lustre_eacl.h interval_tree.h obd_cksum.h \
-            lu_ref.h lustre_acl.h lustre_cache.h
+            lu_ref.h cl_object.h lustre_acl.h lclient.h
diff --git a/lustre/include/cl_object.h b/lustre/include/cl_object.h
new file mode 100644 (file)
index 0000000..3343139
--- /dev/null
@@ -0,0 +1,3033 @@
+/* -*- 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright  2008 Sun Microsystems, Inc. All rights reserved
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ */
+#ifndef _LUSTRE_CL_OBJECT_H
+#define _LUSTRE_CL_OBJECT_H
+
+/** \defgroup clio clio
+ *
+ * Client objects implement io operations and cache pages.
+ *
+ * Examples: lov and osc are implementations of cl interface.
+ *
+ * Big Theory Statement.
+ *
+ * Layered objects.
+ *
+ * Client implementation is based on the following data-types:
+ *
+ *   - cl_object
+ *
+ *   - cl_page
+ *
+ *   - cl_lock     represents an extent lock on an object.
+ *
+ *   - cl_io       represents high-level i/o activity such as whole read/write
+ *                 system call, or write-out of pages from under the lock being
+ *                 canceled. cl_io has sub-ios that can be stopped and resumed
+ *                 independently, thus achieving high degree of transfer
+ *                 parallelism. Single cl_io can be advanced forward by
+ *                 the multiple threads (although in the most usual case of
+ *                 read/write system call it is associated with the single user
+ *                 thread, that issued the system call).
+ *
+ *   - cl_req      represents a collection of pages for a transfer. cl_req is
+ *                 constructed by req-forming engine that tries to saturate
+ *                 transport with large and continuous transfers.
+ *
+ * Terminology
+ *
+ *     - to avoid confusion high-level I/O operation like read or write system
+ *     call is referred to as "an io", whereas low-level I/O operation, like
+ *     RPC, is referred to as "a transfer"
+ *
+ *     - "generic code" means generic (not file system specific) code in the
+ *     hosting environment. "cl-code" means code (mostly in cl_*.c files) that
+ *     is not layer specific.
+ *
+ * Locking.
+ *
+ *  - i_mutex
+ *      - PG_locked
+ *          - cl_object_header::coh_page_guard
+ *          - cl_object_header::coh_lock_guard
+ *          - lu_site::ls_guard
+ *
+ * See the top comment in cl_object.c for the description of overall locking and
+ * reference-counting design.
+ *
+ * See comments below for the description of i/o, page, and dlm-locking
+ * design.
+ *
+ * @{
+ */
+
+/*
+ * super-class definitions.
+ */
+#include <lu_object.h>
+#include <lvfs.h>
+#ifdef __KERNEL__
+#        include <linux/mutex.h>
+#        include <linux/radix-tree.h>
+#endif
+
+struct inode;
+
+struct cl_device;
+struct cl_device_operations;
+
+struct cl_object;
+struct cl_object_page_operations;
+struct cl_object_lock_operations;
+
+struct cl_page;
+struct cl_page_slice;
+struct cl_lock;
+struct cl_lock_slice;
+
+struct cl_lock_operations;
+struct cl_page_operations;
+
+struct cl_io;
+struct cl_io_slice;
+
+struct cl_req;
+struct cl_req_slice;
+
+/**
+ * Operations for each data device in the client stack.
+ *
+ * \see vvp_cl_ops, lov_cl_ops, lovsub_cl_ops, osc_cl_ops
+ */
+struct cl_device_operations {
+        /**
+         * Initialize cl_req. This method is called top-to-bottom on all
+         * devices in the stack to get them a chance to allocate layer-private
+         * data, and to attach them to the cl_req by calling
+         * cl_req_slice_add().
+         *
+         * \see osc_req_init(), lov_req_init(), lovsub_req_init()
+         * \see ccc_req_init()
+         */
+        int (*cdo_req_init)(const struct lu_env *env, struct cl_device *dev,
+                            struct cl_req *req);
+};
+
+/**
+ * Device in the client stack.
+ *
+ * \see ccc_device, lov_device, lovsub_device, osc_device
+ */
+struct cl_device {
+        /** Super-class. */
+        struct lu_device                   cd_lu_dev;
+        /** Per-layer operation vector. */
+        const struct cl_device_operations *cd_ops;
+};
+
+/** \addtogroup cl_object cl_object
+ * @{ */
+/**
+ * "Data attributes" of cl_object. Data attributes can be updated
+ * independently for a sub-object, and top-object's attributes are calculated
+ * from sub-objects' ones.
+ */
+struct cl_attr {
+        /** Object size, in bytes */
+        loff_t cat_size;
+        /**
+         * Known minimal size, in bytes.
+         *
+         * This is only valid when at least one DLM lock is held.
+         */
+        loff_t cat_kms;
+        /** Modification time. Measured in seconds since epoch. */
+        time_t cat_mtime;
+        /** Access time. Measured in seconds since epoch. */
+        time_t cat_atime;
+        /** Change time. Measured in seconds since epoch. */
+        time_t cat_ctime;
+        /**
+         * Blocks allocated to this cl_object on the server file system.
+         *
+         * \todo XXX An interface for block size is needed.
+         */
+        __u64  cat_blocks;
+        /**
+         * User identifier for quota purposes.
+         */
+        uid_t  cat_uid;
+        /**
+         * Group identifier for quota purposes.
+         */
+        gid_t  cat_gid;
+};
+
+/**
+ * Fields in cl_attr that are being set.
+ */
+enum cl_attr_valid {
+        CAT_SIZE   = 1 << 0,
+        CAT_KMS    = 1 << 1,
+        CAT_MTIME  = 1 << 3,
+        CAT_ATIME  = 1 << 4,
+        CAT_CTIME  = 1 << 5,
+        CAT_BLOCKS = 1 << 6,
+        CAT_UID    = 1 << 7,
+        CAT_GID    = 1 << 8
+};
+
+/**
+ * Sub-class of lu_object with methods common for objects on the client
+ * stacks.
+ *
+ * cl_object: represents a regular file system object, both a file and a
+ *    stripe. cl_object is based on lu_object: it is identified by a fid,
+ *    layered, cached, hashed, and lrued. Important distinction with the server
+ *    side, where md_object and dt_object are used, is that cl_object "fans out"
+ *    at the lov/sns level: depending on the file layout, single file is
+ *    represented as a set of "sub-objects" (stripes). At the implementation
+ *    level, struct lov_object contains an array of cl_objects. Each sub-object
+ *    is a full-fledged cl_object, having its fid, living in the lru and hash
+ *    table.
+ *
+ *    This leads to the next important difference with the server side: on the
+ *    client, it's quite usual to have objects with the different sequence of
+ *    layers. For example, typical top-object is composed of the following
+ *    layers:
+ *
+ *        - vvp
+ *        - lov
+ *
+ *    whereas its sub-objects are composed of
+ *
+ *        - lovsub
+ *        - osc
+ *
+ *    layers. Here "lovsub" is a mostly dummy layer, whose purpose is to keep
+ *    track of the object-subobject relationship.
+ *
+ *    Sub-objects are not cached independently: when top-object is about to
+ *    be discarded from the memory, all its sub-objects are torn-down and
+ *    destroyed too.
+ *
+ * \see ccc_object, lov_object, lovsub_object, osc_object
+ */
+struct cl_object {
+        /** super class */
+        struct lu_object                   co_lu;
+        /** per-object-layer operations */
+        const struct cl_object_operations *co_ops;
+};
+
+/**
+ * Description of the client object configuration. This is used for the
+ * creation of a new client object that is identified by a more state than
+ * fid.
+ */
+struct cl_object_conf {
+        /** Super-class. */
+        struct lu_object_conf     coc_lu;
+        union {
+                /**
+                 * Object layout. This is consumed by lov.
+                 */
+                struct lustre_md *coc_md;
+                /**
+                 * Description of particular stripe location in the
+                 * cluster. This is consumed by osc.
+                 */
+                struct lov_oinfo *coc_oinfo;
+        } u;
+        /**
+         * VFS inode. This is consumed by vvp.
+         */
+        struct inode             *coc_inode;
+};
+
+/**
+ * Operations implemented for each cl object layer.
+ *
+ * \see vvp_ops, lov_ops, lovsub_ops, osc_ops
+ */
+struct cl_object_operations {
+        /**
+         * Initialize page slice for this layer. Called top-to-bottom through
+         * every object layer when a new cl_page is instantiated. Layer
+         * keeping private per-page data, or requiring its own page operations
+         * vector should allocate these data here, and attach then to the page
+         * by calling cl_page_slice_add(). \a vmpage is locked (in the VM
+         * sense). Optional.
+         *
+         * \retval NULL success.
+         *
+         * \retval ERR_PTR(errno) failure code.
+         *
+         * \retval valid-pointer pointer to already existing referenced page
+         *         to be used instead of newly created.
+         */
+        struct cl_page *(*coo_page_init)(const struct lu_env *env,
+                                         struct cl_object *obj,
+                                         struct cl_page *page,
+                                         cfs_page_t *vmpage);
+        /**
+         * Initialize lock slice for this layer. Called top-to-bottom through
+         * every object layer when a new cl_lock is instantiated. Layer
+         * keeping private per-lock data, or requiring its own lock operations
+         * vector should allocate these data here, and attach then to the lock
+         * by calling cl_lock_slice_add(). Mandatory.
+         */
+        int  (*coo_lock_init)(const struct lu_env *env,
+                              struct cl_object *obj, struct cl_lock *lock,
+                              const struct cl_io *io);
+        /**
+         * Initialize io state for a given layer.
+         *
+         * called top-to-bottom once per io existence to initialize io
+         * state. If layer wants to keep some state for this type of io, it
+         * has to embed struct cl_io_slice in lu_env::le_ses, and register
+         * slice with cl_io_slice_add(). It is guaranteed that all threads
+         * participating in this io share the same session.
+         */
+        int  (*coo_io_init)(const struct lu_env *env,
+                            struct cl_object *obj, struct cl_io *io);
+        /**
+         * Fill portion of \a attr that this layer controls. This method is
+         * called top-to-bottom through all object layers.
+         *
+         * \pre cl_object_header::coh_attr_guard of the top-object is locked.
+         *
+         * \return   0: to continue
+         * \return +ve: to stop iterating through layers (but 0 is returned
+         * from enclosing cl_object_attr_get())
+         * \return -ve: to signal error
+         */
+        int (*coo_attr_get)(const struct lu_env *env, struct cl_object *obj,
+                            struct cl_attr *attr);
+        /**
+         * Update attributes.
+         *
+         * \a valid is a bitmask composed from enum #cl_attr_valid, and
+         * indicating what attributes are to be set.
+         *
+         * \pre cl_object_header::coh_attr_guard of the top-object is locked.
+         *
+         * \return the same convention as for
+         * cl_object_operations::coo_attr_get() is used.
+         */
+        int (*coo_attr_set)(const struct lu_env *env, struct cl_object *obj,
+                            const struct cl_attr *attr, unsigned valid);
+        /**
+         * Update object configuration. Called top-to-bottom to modify object
+         * configuration.
+         *
+         * XXX error conditions and handling.
+         */
+        int (*coo_conf_set)(const struct lu_env *env, struct cl_object *obj,
+                            const struct cl_object_conf *conf);
+        /**
+         * Glimpse ast. Executed when glimpse ast arrives for a lock on this
+         * object. Layers are supposed to fill parts of \a lvb that will be
+         * shipped to the glimpse originator as a glimpse result.
+         *
+         * \see ccc_object_glimpse(), lovsub_object_glimpse(),
+         * \see osc_object_glimpse()
+         */
+        int (*coo_glimpse)(const struct lu_env *env,
+                           const struct cl_object *obj, struct ost_lvb *lvb);
+};
+
+/**
+ * Extended header for client object.
+ */
+struct cl_object_header {
+        /** Standard lu_object_header. cl_object::co_lu::lo_header points
+         * here. */
+        struct lu_object_header  coh_lu;
+        /** \name locks
+         * \todo XXX move locks below to the separate cache-lines, they are
+         * mostly useless otherwise.
+         */
+        /** @{ */
+        /** Lock protecting page tree. */
+        spinlock_t               coh_page_guard;
+        /** Lock protecting lock list. */
+        spinlock_t               coh_lock_guard;
+        /** @} locks */
+        /** Radix tree of cl_page's, cached for this object. */
+        struct radix_tree_root   coh_tree;
+        /** # of pages in radix tree. */
+        unsigned long            coh_pages;
+        /** List of cl_lock's granted for this object. */
+        struct list_head         coh_locks;
+
+        /**
+         * Parent object. It is assumed that an object has a well-defined
+         * parent, but not a well-defined child (there may be multiple
+         * sub-objects, for the same top-object). cl_object_header::coh_parent
+         * field allows certain code to be written generically, without
+         * limiting possible cl_object layouts unduly.
+         */
+        struct cl_object_header *coh_parent;
+        /**
+         * Protects consistency between cl_attr of parent object and
+         * attributes of sub-objects, that the former is calculated ("merged")
+         * from.
+         *
+         * \todo XXX this can be read/write lock if needed.
+         */
+        spinlock_t               coh_attr_guard;
+        /**
+         * Number of objects above this one: 0 for a top-object, 1 for its
+         * sub-object, etc.
+         */
+        unsigned                 coh_nesting;
+};
+
+/**
+ * Helper macro: iterate over all layers of the object \a obj, assigning every
+ * layer top-to-bottom to \a slice.
+ */
+#define cl_object_for_each(slice, obj)                                  \
+        list_for_each_entry((slice),                                    \
+                            &(obj)->co_lu.lo_header->loh_layers,        \
+                            co_lu.lo_linkage)
+/**
+ * Helper macro: iterate over all layers of the object \a obj, assigning every
+ * layer bottom-to-top to \a slice.
+ */
+#define cl_object_for_each_reverse(slice, obj)                          \
+        list_for_each_entry_reverse((slice),                            \
+                                    &(obj)->co_lu.lo_header->loh_layers, \
+                                    co_lu.lo_linkage)
+/** @} cl_object */
+
+#ifndef pgoff_t
+#define pgoff_t unsigned long
+#endif
+
+#define CL_PAGE_EOF ((pgoff_t)~0ull)
+
+/** \addtogroup cl_page cl_page
+ * @{ */
+
+/** \struct cl_page
+ * Layered client page.
+ *
+ * cl_page: represents a portion of a file, cached in the memory. All pages
+ *    of the given file are of the same size, and are kept in the radix tree
+ *    hanging off the cl_object. cl_page doesn't fan out, but as sub-objects
+ *    of the top-level file object are first class cl_objects, they have their
+ *    own radix trees of pages and hence page is implemented as a sequence of
+ *    struct cl_pages's, linked into double-linked list through
+ *    cl_page::cp_parent and cl_page::cp_child pointers, each residing in the
+ *    corresponding radix tree at the corresponding logical offset.
+ *
+ * cl_page is associated with VM page of the hosting environment (struct
+ *    page in Linux kernel, for example), cfs_page_t. It is assumed, that this
+ *    association is implemented by one of cl_page layers (top layer in the
+ *    current design) that
+ *
+ *        - intercepts per-VM-page call-backs made by the environment (e.g.,
+ *          memory pressure),
+ *
+ *        - translates state (page flag bits) and locking between lustre and
+ *          environment.
+ *
+ *    The association between cl_page and cfs_page_t is immutable and
+ *    established when cl_page is created.
+ *
+ * cl_page can be "owned" by a particular cl_io (see below), guaranteeing
+ *    this io an exclusive access to this page w.r.t. other io attempts and
+ *    various events changing page state (such as transfer completion, or
+ *    eviction of the page from the memory). Note, that in general cl_io
+ *    cannot be identified with a particular thread, and page ownership is not
+ *    exactly equal to the current thread holding a lock on the page. Layer
+ *    implementing association between cl_page and cfs_page_t has to implement
+ *    ownership on top of available synchronization mechanisms.
+ *
+ *    While lustre client maintains the notion of an page ownership by io,
+ *    hosting MM/VM usually has its own page concurrency control
+ *    mechanisms. For example, in Linux, page access is synchronized by the
+ *    per-page PG_locked bit-lock, and generic kernel code (generic_file_*())
+ *    takes care to acquire and release such locks as necessary around the
+ *    calls to the file system methods (->readpage(), ->prepare_write(),
+ *    ->commit_write(), etc.). This leads to the situation when there are two
+ *    different ways to own a page in the client:
+ *
+ *        - client code explicitly and voluntary owns the page (cl_page_own());
+ *
+ *        - VM locks a page and then calls the client, that has "to assume"
+ *          the ownership from the VM (cl_page_assume()).
+ *
+ *    Dual methods to release ownership are cl_page_disown() and
+ *    cl_page_unassume().
+ *
+ * cl_page is reference counted (cl_page::cp_ref). When reference counter
+ *    drops to 0, the page is returned to the cache, unless it is in
+ *    cl_page_state::CPS_FREEING state, in which case it is immediately
+ *    destroyed.
+ *
+ *    The general logic guaranteeing the absence of "existential races" for
+ *    pages is the following:
+ *
+ *        - there are fixed known ways for a thread to obtain a new reference
+ *          to a page:
+ *
+ *            - by doing a lookup in the cl_object radix tree, protected by the
+ *              spin-lock;
+ *
+ *            - by starting from VM-locked cfs_page_t and following some
+ *              hosting environment method (e.g., following ->private pointer in
+ *              the case of Linux kernel), see cl_vmpage_page();
+ *
+ *        - when the page enters cl_page_state::CPS_FREEING state, all these
+ *          ways are severed with the proper synchronization
+ *          (cl_page_delete());
+ *
+ *        - entry into cl_page_state::CPS_FREEING is serialized by the VM page
+ *          lock;
+ *
+ *        - no new references to the page in cl_page_state::CPS_FREEING state
+ *          are allowed (checked in cl_page_get()).
+ *
+ *    Together this guarantees that when last reference to a
+ *    cl_page_state::CPS_FREEING page is released, it is safe to destroy the
+ *    page, as neither references to it can be acquired at that point, nor
+ *    ones exist.
+ *
+ * cl_page is a state machine. States are enumerated in enum
+ *    cl_page_state. Possible state transitions are enumerated in
+ *    cl_page_state_set(). State transition process (i.e., actual changing of
+ *    cl_page::cp_state field) is protected by the lock on the underlying VM
+ *    page.
+ *
+ * Linux Kernel implementation.
+ *
+ *    Binding between cl_page and cfs_page_t (which is a typedef for
+ *    struct page) is implemented in the vvp layer. cl_page is attached to the
+ *    ->private pointer of the struct page, together with the setting of
+ *    PG_private bit in page->flags, and acquiring additional reference on the
+ *    struct page (much like struct buffer_head, or any similar file system
+ *    private data structures).
+ *
+ *    PG_locked lock is used to implement both ownership and transfer
+ *    synchronization, that is, page is VM-locked in CPS_{OWNED,PAGE{IN,OUT}}
+ *    states. No additional references are acquired for the duration of the
+ *    transfer.
+ *
+ * \warning *THIS IS NOT* the behavior expected by the Linux kernel, where
+ *          write-out is "protected" by the special PG_writeback bit.
+ */
+
+/**
+ * States of cl_page. cl_page.c assumes particular order here.
+ *
+ * The page state machine is rather crude, as it doesn't recognize finer page
+ * states like "dirty" or "up to date". This is because such states are not
+ * always well defined for the whole stack (see, for example, the
+ * implementation of the read-ahead, that hides page up-to-dateness to track
+ * cache hits accurately). Such sub-states are maintained by the layers that
+ * are interested in them.
+ */
+enum cl_page_state {
+        /**
+         * Page is in the cache, un-owned. Page leaves cached state in the
+         * following cases:
+         *
+         *     - [cl_page_state::CPS_OWNED] io comes across the page and
+         *     owns it;
+         *
+         *     - [cl_page_state::CPS_PAGEOUT] page is dirty, the
+         *     req-formation engine decides that it wants to include this page
+         *     into an cl_req being constructed, and yanks it from the cache;
+         *
+         *     - [cl_page_state::CPS_FREEING] VM callback is executed to
+         *     evict the page form the memory;
+         *
+         * \invariant cl_page::cp_owner == NULL && cl_page::cp_req == NULL
+         */
+        CPS_CACHED,
+        /**
+         * Page is exclusively owned by some cl_io. Page may end up in this
+         * state as a result of
+         *
+         *     - io creating new page and immediately owning it;
+         *
+         *     - [cl_page_state::CPS_CACHED] io finding existing cached page
+         *     and owning it;
+         *
+         *     - [cl_page_state::CPS_OWNED] io finding existing owned page
+         *     and waiting for owner to release the page;
+         *
+         * Page leaves owned state in the following cases:
+         *
+         *     - [cl_page_state::CPS_CACHED] io decides to leave the page in
+         *     the cache, doing nothing;
+         *
+         *     - [cl_page_state::CPS_PAGEIN] io starts read transfer for
+         *     this page;
+         *
+         *     - [cl_page_state::CPS_PAGEOUT] io starts immediate write
+         *     transfer for this page;
+         *
+         *     - [cl_page_state::CPS_FREEING] io decides to destroy this
+         *     page (e.g., as part of truncate or extent lock cancellation).
+         *
+         * \invariant cl_page::cp_owner != NULL && cl_page::cp_req == NULL
+         */
+        CPS_OWNED,
+        /**
+         * Page is being written out, as a part of a transfer. This state is
+         * entered when req-formation logic decided that it wants this page to
+         * be sent through the wire _now_. Specifically, it means that once
+         * this state is achieved, transfer completion handler (with either
+         * success or failure indication) is guaranteed to be executed against
+         * this page independently of any locks and any scheduling decisions
+         * made by the hosting environment (that effectively means that the
+         * page is never put into cl_page_state::CPS_PAGEOUT state "in
+         * advance". This property is mentioned, because it is important when
+         * reasoning about possible dead-locks in the system). The page can
+         * enter this state as a result of
+         *
+         *     - [cl_page_state::CPS_OWNED] an io requesting an immediate
+         *     write-out of this page, or
+         *
+         *     - [cl_page_state::CPS_CACHED] req-forming engine deciding
+         *     that it has enough dirty pages cached to issue a "good"
+         *     transfer.
+         *
+         * The page leaves cl_page_state::CPS_PAGEOUT state when the transfer
+         * is completed---it is moved into cl_page_state::CPS_CACHED state.
+         *
+         * Underlying VM page is locked for the duration of transfer.
+         *
+         * \invariant: cl_page::cp_owner == NULL && cl_page::cp_req != NULL
+         */
+        CPS_PAGEOUT,
+        /**
+         * Page is being read in, as a part of a transfer. This is quite
+         * similar to the cl_page_state::CPS_PAGEOUT state, except that
+         * read-in is always "immediate"---there is no such thing a sudden
+         * construction of read cl_req from cached, presumably not up to date,
+         * pages.
+         *
+         * Underlying VM page is locked for the duration of transfer.
+         *
+         * \invariant: cl_page::cp_owner == NULL && cl_page::cp_req != NULL
+         */
+        CPS_PAGEIN,
+        /**
+         * Page is being destroyed. This state is entered when client decides
+         * that page has to be deleted from its host object, as, e.g., a part
+         * of truncate.
+         *
+         * Once this state is reached, there is no way to escape it.
+         *
+         * \invariant: cl_page::cp_owner == NULL && cl_page::cp_req == NULL
+         */
+        CPS_FREEING,
+        CPS_NR
+};
+
+enum cl_page_type {
+        /** Host page, the page is from the host inode which the cl_page
+         * belongs to. */
+        CPT_CACHEABLE = 1,
+
+        /** Transient page, the transient cl_page is used to bind a cl_page
+         *  to vmpage which is not belonging to the same object of cl_page.
+         *  it is used in DirectIO, lockless IO and liblustre. */
+        CPT_TRANSIENT,
+};
+
+/**
+ * Flags maintained for every cl_page.
+ */
+enum cl_page_flags {
+        /**
+         * Set when pagein completes. Used for debugging (read completes at
+         * most once for a page).
+         */
+        CPF_READ_COMPLETED = 1 << 0
+};
+
+/**
+ * Fields are protected by the lock on cfs_page_t, except for atomics and
+ * immutables.
+ *
+ * \invariant Data type invariants are in cl_page_invariant(). Basically:
+ * cl_page::cp_parent and cl_page::cp_child are a well-formed double-linked
+ * list, consistent with the parent/child pointers in the cl_page::cp_obj and
+ * cl_page::cp_owner (when set).
+ */
+struct cl_page {
+        /** Reference counter. */
+        atomic_t                 cp_ref;
+        /** An object this page is a part of. Immutable after creation. */
+        struct cl_object        *cp_obj;
+        /** Logical page index within the object. Immutable after creation. */
+        pgoff_t                  cp_index;
+        /** List of slices. Immutable after creation. */
+        struct list_head         cp_layers;
+        /** Parent page, NULL for top-level page. Immutable after creation. */
+        struct cl_page          *cp_parent;
+        /** Lower-layer page. NULL for bottommost page. Immutable after
+         * creation. */
+        struct cl_page          *cp_child;
+        /**
+         * Page state. This field is const to avoid accidental update, it is
+         * modified only internally within cl_page.c. Protected by a VM lock.
+         */
+        const enum cl_page_state cp_state;
+        /**
+         * Linkage of pages within some group. Protected by
+         * cl_page::cp_mutex. */
+        struct list_head         cp_batch;
+        /** Mutex serializing membership of a page in a batch. */
+        struct mutex             cp_mutex;
+        /** Linkage of pages within cl_req. */
+        struct list_head         cp_flight;
+        /** Transfer error. */
+        int                      cp_error;
+
+        /**
+         * Page type. Only CPT_TRANSIENT is used so far. Immutable after
+         * creation.
+         */
+        enum cl_page_type        cp_type;
+
+        /**
+         * Owning IO in cl_page_state::CPS_OWNED state. Sub-page can be owned
+         * by sub-io. Protected by a VM lock.
+         */
+        struct cl_io            *cp_owner;
+        /**
+         * Owning IO request in cl_page_state::CPS_PAGEOUT and
+         * cl_page_state::CPS_PAGEIN states. This field is maintained only in
+         * the top-level pages. Protected by a VM lock.
+         */
+        struct cl_req           *cp_req;
+        /** List of references to this page, for debugging. */
+        struct lu_ref            cp_reference;
+        /** Link to an object, for debugging. */
+        struct lu_ref_link      *cp_obj_ref;
+        /** Link to a queue, for debugging. */
+        struct lu_ref_link      *cp_queue_ref;
+        /** Per-page flags from enum cl_page_flags. Protected by a VM lock. */
+        unsigned                 cp_flags;
+};
+
+/**
+ * Per-layer part of cl_page.
+ *
+ * \see ccc_page, lov_page, osc_page
+ */
+struct cl_page_slice {
+        struct cl_page                  *cpl_page;
+        /**
+         * Object slice corresponding to this page slice. Immutable after
+         * creation.
+         */
+        struct cl_object                *cpl_obj;
+        const struct cl_page_operations *cpl_ops;
+        /** Linkage into cl_page::cp_layers. Immutable after creation. */
+        struct list_head                 cpl_linkage;
+};
+
+/**
+ * Lock mode. For the client extent locks.
+ *
+ * \warning: cl_lock_mode_match() assumes particular ordering here.
+ * \ingroup cl_lock
+ */
+enum cl_lock_mode {
+        /**
+         * Mode of a lock that protects no data, and exists only as a
+         * placeholder. This is used for `glimpse' requests. A phantom lock
+         * might get promoted to real lock at some point.
+         */
+        CLM_PHANTOM,
+        CLM_READ,
+        CLM_WRITE
+};
+
+/**
+ * Requested transfer type.
+ * \ingroup cl_req
+ */
+enum cl_req_type {
+        CRT_READ,
+        CRT_WRITE,
+        CRT_NR
+};
+
+/**
+ * Per-layer page operations.
+ *
+ * Methods taking an \a io argument are for the activity happening in the
+ * context of given \a io. Page is assumed to be owned by that io, except for
+ * the obvious cases (like cl_page_operations::cpo_own()).
+ *
+ * \see vvp_page_ops, lov_page_ops, osc_page_ops
+ */
+struct cl_page_operations {
+        /**
+         * cl_page<->cfs_page_t methods. Only one layer in the stack has to
+         * implement these. Current code assumes that this functionality is
+         * provided by the topmost layer, see cl_page_disown0() as an example.
+         */
+
+        /**
+         * \return the underlying VM page. Optional.
+         */
+        cfs_page_t *(*cpo_vmpage)(const struct lu_env *env,
+                                  const struct cl_page_slice *slice);
+        /**
+         * Called when \a io acquires this page into the exclusive
+         * ownership. When this method returns, it is guaranteed that the is
+         * not owned by other io, and no transfer is going on against
+         * it. Optional.
+         *
+         * \see cl_page_own()
+         * \see vvp_page_own(), lov_page_own()
+         */
+        void (*cpo_own)(const struct lu_env *env,
+                        const struct cl_page_slice *slice, struct cl_io *io);
+        /** Called when ownership it yielded. Optional.
+         *
+         * \see cl_page_disown()
+         * \see vvp_page_disown()
+         */
+        void (*cpo_disown)(const struct lu_env *env,
+                           const struct cl_page_slice *slice, struct cl_io *io);
+        /**
+         * Called for a page that is already "owned" by \a io from VM point of
+         * view. Optional.
+         *
+         * \see cl_page_assume()
+         * \see vvp_page_assume(), lov_page_assume()
+         */
+        void (*cpo_assume)(const struct lu_env *env,
+                           const struct cl_page_slice *slice, struct cl_io *io);
+        /** Dual to cl_page_operations::cpo_assume(). Optional. Called
+         * bottom-to-top when IO releases a page without actually unlocking
+         * it.
+         *
+         * \see cl_page_unassume()
+         * \see vvp_page_unassume()
+         */
+        void (*cpo_unassume)(const struct lu_env *env,
+                             const struct cl_page_slice *slice,
+                             struct cl_io *io);
+        /**
+         * Announces that page contains valid data and user space can look and
+         * them without client's involvement from now on. Effectively marks
+         * the page up-to-date. Optional.
+         *
+         * \see cl_page_export()
+         * \see vvp_page_export()
+         */
+        void  (*cpo_export)(const struct lu_env *env,
+                            const struct cl_page_slice *slice);
+        /**
+         * Unmaps page from the user space (if it is mapped).
+         *
+         * \see cl_page_unmap()
+         * \see vvp_page_unmap()
+         */
+        int (*cpo_unmap)(const struct lu_env *env,
+                         const struct cl_page_slice *slice, struct cl_io *io);
+        /**
+         * Checks whether underlying VM page is locked (in the suitable
+         * sense). Used for assertions.
+         *
+         * \retval    -EBUSY: page is protected by a lock of a given mode;
+         * \retval  -ENODATA: page is not protected by a lock;
+         * \retval         0: this layer cannot decide. (Should never happen.)
+         */
+        int (*cpo_is_vmlocked)(const struct lu_env *env,
+                               const struct cl_page_slice *slice);
+        /**
+         * Page destruction.
+         */
+
+        /**
+         * Called when page is truncated from the object. Optional.
+         *
+         * \see cl_page_discard()
+         * \see vvp_page_discard(), osc_page_discard()
+         */
+        void (*cpo_discard)(const struct lu_env *env,
+                            const struct cl_page_slice *slice,
+                            struct cl_io *io);
+        /**
+         * Called when page is removed from the cache, and is about to being
+         * destroyed. Optional.
+         *
+         * \see cl_page_delete()
+         * \see vvp_page_delete(), osc_page_delete()
+         */
+        void (*cpo_delete)(const struct lu_env *env,
+                           const struct cl_page_slice *slice);
+        /** Destructor. Frees resources and slice itself. */
+        void (*cpo_fini)(const struct lu_env *env,
+                         struct cl_page_slice *slice);
+
+        /**
+         * Checks whether the page is protected by a cl_lock. This is a
+         * per-layer method, because certain layers have ways to check for the
+         * lock much more efficiently than through the generic locks scan, or
+         * implement locking mechanisms separate from cl_lock, e.g.,
+         * LL_FILE_GROUP_LOCKED in vvp. If \a pending is true, check for locks
+         * being canceled, or scheduled for cancellation as soon as the last
+         * user goes away, too.
+         *
+         * \retval    -EBUSY: page is protected by a lock of a given mode;
+         * \retval  -ENODATA: page is not protected by a lock;
+         * \retval         0: this layer cannot decide.
+         *
+         * \see cl_page_is_under_lock()
+         */
+        int (*cpo_is_under_lock)(const struct lu_env *env,
+                                 const struct cl_page_slice *slice,
+                                 struct cl_io *io);
+
+        /**
+         * Optional debugging helper. Prints given page slice.
+         *
+         * \see cl_page_print()
+         */
+        int (*cpo_print)(const struct lu_env *env,
+                         const struct cl_page_slice *slice,
+                         void *cookie, lu_printer_t p);
+        /**
+         * \name transfer
+         *
+         * Transfer methods. See comment on cl_req for a description of
+         * transfer formation and life-cycle.
+         *
+         * @{
+         */
+        /**
+         * Request type dependent vector of operations.
+         *
+         * Transfer operations depend on transfer mode (cl_req_type). To avoid
+         * passing transfer mode to each and every of these methods, and to
+         * avoid branching on request type inside of the methods, separate
+         * methods for cl_req_type:CRT_READ and cl_req_type:CRT_WRITE are
+         * provided. That is, method invocation usually looks like
+         *
+         *         slice->cp_ops.io[req->crq_type].cpo_method(env, slice, ...);
+         */
+        struct {
+                /**
+                 * Called when a page is submitted for a transfer as a part of
+                 * cl_page_list.
+                 *
+                 * \return    0         : page is eligible for submission;
+                 * \return    -EALREADY : skip this page;
+                 * \return    -ve       : error.
+                 *
+                 * \see cl_page_prep()
+                 */
+                int  (*cpo_prep)(const struct lu_env *env,
+                                 const struct cl_page_slice *slice,
+                                 struct cl_io *io);
+                /**
+                 * Completion handler. This is guaranteed to be eventually
+                 * fired after cl_page_operations::cpo_prep() or
+                 * cl_page_operations::cpo_make_ready() call.
+                 *
+                 * This method can be called in a non-blocking context. It is
+                 * guaranteed however, that the page involved and its object
+                 * are pinned in memory (and, hence, calling cl_page_put() is
+                 * safe).
+                 *
+                 * \see cl_page_completion()
+                 */
+                void (*cpo_completion)(const struct lu_env *env,
+                                       const struct cl_page_slice *slice,
+                                       int ioret);
+                /**
+                 * Called when cached page is about to be added to the
+                 * cl_req as a part of req formation.
+                 *
+                 * \return    0       : proceed with this page;
+                 * \return    -EAGAIN : skip this page;
+                 * \return    -ve     : error.
+                 *
+                 * \see cl_page_make_ready()
+                 */
+                int  (*cpo_make_ready)(const struct lu_env *env,
+                                       const struct cl_page_slice *slice);
+                /**
+                 * Announce that this page is to be written out
+                 * opportunistically, that is, page is dirty, it is not
+                 * necessary to start write-out transfer right now, but
+                 * eventually page has to be written out.
+                 *
+                 * Main caller of this is the write path (see
+                 * vvp_io_commit_write()), using this method to build a
+                 * "transfer cache" from which large transfers are then
+                 * constructed by the req-formation engine.
+                 *
+                 * \todo XXX it would make sense to add page-age tracking
+                 * semantics here, and to oblige the req-formation engine to
+                 * send the page out not later than it is too old.
+                 *
+                 * \see cl_page_cache_add()
+                 */
+                int  (*cpo_cache_add)(const struct lu_env *env,
+                                      const struct cl_page_slice *slice,
+                                      struct cl_io *io);
+        } io[CRT_NR];
+        /**
+         * Tell transfer engine that only [to, from] part of a page should be
+         * transmitted.
+         *
+         * This is used for immediate transfers.
+         *
+         * \todo XXX this is not very good interface. It would be much better
+         * if all transfer parameters were supplied as arguments to
+         * cl_io_operations::cio_submit() call, but it is not clear how to do
+         * this for page queues.
+         *
+         * \see cl_page_clip()
+         */
+        void (*cpo_clip)(const struct lu_env *env,
+                         const struct cl_page_slice *slice,
+                         int from, int to);
+        /**
+         * \pre  the page was queued for transferring.
+         * \post page is removed from client's pending list, or -EBUSY
+         *       is returned if it has already been in transferring.
+         *
+         * This is one of seldom page operation which is:
+         * 0. called from top level;
+         * 1. don't have vmpage locked;
+         * 2. every layer should synchronize execution of its ->cpo_cancel()
+         *    with completion handlers. Osc uses client obd lock for this
+         *    purpose. Based on there is no vvp_page_cancel and
+         *    lov_page_cancel(), cpo_cancel is defacto protected by client lock.
+         *
+         * \see osc_page_cancel().
+         */
+        int (*cpo_cancel)(const struct lu_env *env,
+                          const struct cl_page_slice *slice);
+        /** @} transfer */
+};
+
+/**
+ * Helper macro, dumping detailed information about \a page into a log.
+ */
+#define CL_PAGE_DEBUG(mask, env, page, format, ...)                     \
+do {                                                                    \
+        static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask);              \
+                                                                        \
+        if (cdebug_show(mask, DEBUG_SUBSYSTEM)) {                       \
+                cl_page_print(env, &__info, lu_cdebug_printer, page);   \
+                CDEBUG(mask, format , ## __VA_ARGS__);                  \
+        }                                                               \
+} while (0)
+
+/**
+ * Helper macro, dumping shorter information about \a page into a log.
+ */
+#define CL_PAGE_HEADER(mask, env, page, format, ...)                    \
+do {                                                                    \
+        static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask);              \
+                                                                        \
+        if (cdebug_show(mask, DEBUG_SUBSYSTEM)) {                       \
+                cl_page_header_print(env, &__info, lu_cdebug_printer, page); \
+                CDEBUG(mask, format , ## __VA_ARGS__);                  \
+        }                                                               \
+} while (0)
+
+/** @} cl_page */
+
+/** \addtogroup cl_lock cl_lock
+ * @{ */
+/** \struct cl_lock
+ *
+ * Extent locking on the client.
+ *
+ * LAYERING
+ *
+ * The locking model of the new client code is built around
+ *
+ *        struct cl_lock
+ *
+ * data-type representing an extent lock on a regular file. cl_lock is a
+ * layered object (much like cl_object and cl_page), it consists of a header
+ * (struct cl_lock) and a list of layers (struct cl_lock_slice), linked to
+ * cl_lock::cll_layers list through cl_lock_slice::cls_linkage.
+ *
+ * All locks for a given object are linked into cl_object_header::coh_locks
+ * list (protected by cl_object_header::coh_lock_guard spin-lock) through
+ * cl_lock::cll_linkage. Currently this list is not sorted in any way. We can
+ * sort it in starting lock offset, or use altogether different data structure
+ * like a tree.
+ *
+ * Typical cl_lock consists of the two layers:
+ *
+ *     - vvp_lock (vvp specific data), and
+ *     - lov_lock (lov specific data).
+ *
+ * lov_lock contains an array of sub-locks. Each of these sub-locks is a
+ * normal cl_lock: it has a header (struct cl_lock) and a list of layers:
+ *
+ *     - lovsub_lock, and
+ *     - osc_lock
+ *
+ * Each sub-lock is associated with a cl_object (representing stripe
+ * sub-object or the file to which top-level cl_lock is associated to), and is
+ * linked into that cl_object::coh_locks. In this respect cl_lock is similar to
+ * cl_object (that at lov layer also fans out into multiple sub-objects), and
+ * is different from cl_page, that doesn't fan out (there is usually exactly
+ * one osc_page for every vvp_page). We shall call vvp-lov portion of the lock
+ * a "top-lock" and its lovsub-osc portion a "sub-lock".
+ *
+ * LIFE CYCLE
+ *
+ * cl_lock is reference counted. When reference counter drops to 0, lock is
+ * placed in the cache, except when lock is in CLS_FREEING state. CLS_FREEING
+ * lock is destroyed when last reference is released. Referencing between
+ * top-lock and its sub-locks is described in the lov documentation module.
+ *
+ * STATE MACHINE
+ *
+ * Also, cl_lock is a state machine. This requires some clarification. One of
+ * the goals of client IO re-write was to make IO path non-blocking, or at
+ * least to make it easier to make it non-blocking in the future. Here
+ * `non-blocking' means that when a system call (read, write, truncate)
+ * reaches a situation where it has to wait for a communication with the
+ * server, it should --instead of waiting-- remember its current state and
+ * switch to some other work.  E.g,. instead of waiting for a lock enqueue,
+ * client should proceed doing IO on the next stripe, etc. Obviously this is
+ * rather radical redesign, and it is not planned to be fully implemented at
+ * this time, instead we are putting some infrastructure in place, that would
+ * make it easier to do asynchronous non-blocking IO easier in the
+ * future. Specifically, where old locking code goes to sleep (waiting for
+ * enqueue, for example), new code returns cl_lock_transition::CLO_WAIT. When
+ * enqueue reply comes, its completion handler signals that lock state-machine
+ * is ready to transit to the next state. There is some generic code in
+ * cl_lock.c that sleeps, waiting for these signals. As a result, for users of
+ * this cl_lock.c code, it looks like locking is done in normal blocking
+ * fashion, and it the same time it is possible to switch to the non-blocking
+ * locking (simply by returning cl_lock_transition::CLO_WAIT from cl_lock.c
+ * functions).
+ *
+ * For a description of state machine states and transitions see enum
+ * cl_lock_state.
+ *
+ * There are two ways to restrict a set of states which lock might move to:
+ *
+ *     - placing a "hold" on a lock guarantees that lock will not be moved
+ *       into cl_lock_state::CLS_FREEING state until hold is released. Hold
+ *       can be only acquired on a lock that is not in
+ *       cl_lock_state::CLS_FREEING. All holds on a lock are counted in
+ *       cl_lock::cll_holds. Hold protects lock from cancellation and
+ *       destruction. Requests to cancel and destroy a lock on hold will be
+ *       recorded, but only honored when last hold on a lock is released;
+ *
+ *     - placing a "user" on a lock guarantees that lock will not leave
+ *       cl_lock_state::CLS_NEW, cl_lock_state::CLS_QUEUING,
+ *       cl_lock_state::CLS_ENQUEUED and cl_lock_state::CLS_HELD set of
+ *       states, once it enters this set. That is, if a user is added onto a
+ *       lock in a state not from this set, it doesn't immediately enforce
+ *       lock to move to this set, but once lock enters this set it will
+ *       remain there until all users are removed. Lock users are counted in
+ *       cl_lock::cll_users.
+ *
+ *       User is used to assure that lock is not canceled or destroyed while
+ *       it is being enqueued, or actively used by some IO.
+ *
+ *       Currently, a user always comes with a hold (cl_lock_invariant()
+ *       checks that a number of holds is not less than a number of users).
+ *
+ * CONCURRENCY
+ *
+ * This is how lock state-machine operates. struct cl_lock contains a mutex
+ * cl_lock::cll_guard that protects struct fields.
+ *
+ *     - mutex is taken, and cl_lock::cll_state is examined.
+ *
+ *     - for every state there are possible target states where lock can move
+ *       into. They are tried in order. Attempts to move into next state are
+ *       done by _try() functions in cl_lock.c:cl_{enqueue,unlock,wait}_try().
+ *
+ *     - if the transition can be performed immediately, state is changed,
+ *       and mutex is released.
+ *
+ *     - if the transition requires blocking, _try() function returns
+ *       cl_lock_transition::CLO_WAIT. Caller unlocks mutex and goes to
+ *       sleep, waiting for possibility of lock state change. It is woken
+ *       up when some event occurs, that makes lock state change possible
+ *       (e.g., the reception of the reply from the server), and repeats
+ *       the loop.
+ *
+ * Top-lock and sub-lock has separate mutexes and the latter has to be taken
+ * first to avoid dead-lock.
+ *
+ * To see an example of interaction of all these issues, take a look at the
+ * lov_cl.c:lov_lock_enqueue() function. It is called as a part of
+ * cl_enqueue_try(), and tries to advance top-lock to ENQUEUED state, by
+ * advancing state-machines of its sub-locks (lov_lock_enqueue_one()). Note
+ * also, that it uses trylock to grab sub-lock mutex to avoid dead-lock. It
+ * also has to handle CEF_ASYNC enqueue, when sub-locks enqueues have to be
+ * done in parallel, rather than one after another (this is used for glimpse
+ * locks, that cannot dead-lock).
+ *
+ * INTERFACE AND USAGE
+ *
+ * struct cl_lock_operations provide a number of call-backs that are invoked
+ * when events of interest occurs. Layers can intercept and handle glimpse,
+ * blocking, cancel ASTs and a reception of the reply from the server.
+ *
+ * One important difference with the old client locking model is that new
+ * client has a representation for the top-lock, whereas in the old code only
+ * sub-locks existed as real data structures and file-level locks are
+ * represented by "request sets" that are created and destroyed on each and
+ * every lock creation.
+ *
+ * Top-locks are cached, and can be found in the cache by the system calls. It
+ * is possible that top-lock is in cache, but some of its sub-locks were
+ * canceled and destroyed. In that case top-lock has to be enqueued again
+ * before it can be used.
+ *
+ * Overall process of the locking during IO operation is as following:
+ *
+ *     - once parameters for IO are setup in cl_io, cl_io_operations::cio_lock()
+ *       is called on each layer. Responsibility of this method is to add locks,
+ *       needed by a given layer into cl_io.ci_lockset.
+ *
+ *     - once locks for all layers were collected, they are sorted to avoid
+ *       dead-locks (cl_io_locks_sort()), and enqueued.
+ *
+ *     - when all locks are acquired, IO is performed;
+ *
+ *     - locks are released into cache.
+ *
+ * Striping introduces major additional complexity into locking. The
+ * fundamental problem is that it is generally unsafe to actively use (hold)
+ * two locks on the different OST servers at the same time, as this introduces
+ * inter-server dependency and can lead to cascading evictions.
+ *
+ * Basic solution is to sub-divide large read/write IOs into smaller pieces so
+ * that no multi-stripe locks are taken (note that this design abandons POSIX
+ * read/write semantics). Such pieces ideally can be executed concurrently. At
+ * the same time, certain types of IO cannot be sub-divived, without
+ * sacrificing correctness. This includes:
+ *
+ *  - O_APPEND write, where [0, EOF] lock has to be taken, to guarantee
+ *  atomicity;
+ *
+ *  - ftruncate(fd, offset), where [offset, EOF] lock has to be taken.
+ *
+ * Also, in the case of read(fd, buf, count) or write(fd, buf, count), where
+ * buf is a part of memory mapped Lustre file, a lock or locks protecting buf
+ * has to be held together with the usual lock on [offset, offset + count].
+ *
+ * As multi-stripe locks have to be allowed, it makes sense to cache them, so
+ * that, for example, a sequence of O_APPEND writes can proceed quickly
+ * without going down to the individual stripes to do lock matching. On the
+ * other hand, multi-stripe locks shouldn't be used by normal read/write
+ * calls. To achieve this, every layer can implement ->clo_fits_into() method,
+ * that is called by lock matching code (cl_lock_lookup()), and that can be
+ * used to selectively disable matching of certain locks for certain IOs. For
+ * exmaple, lov layer implements lov_lock_fits_into() that allow multi-stripe
+ * locks to be matched only for truncates and O_APPEND writes.
+ *
+ * Interaction with DLM
+ *
+ * In the expected setup, cl_lock is ultimately backed up by a collection of
+ * DLM locks (struct ldlm_lock). Association between cl_lock and DLM lock is
+ * implemented in osc layer, that also matches DLM events (ASTs, cancellation,
+ * etc.) into cl_lock_operation calls. See struct osc_lock for a more detailed
+ * description of interaction with DLM.
+ */
+
+/**
+ * Lock description.
+ */
+struct cl_lock_descr {
+        /** Object this lock is granted for. */
+        struct cl_object *cld_obj;
+        /** Index of the first page protected by this lock. */
+        pgoff_t           cld_start;
+        /** Index of the last page (inclusive) protected by this lock. */
+        pgoff_t           cld_end;
+        /** Lock mode. */
+        enum cl_lock_mode cld_mode;
+};
+
+#define DDESCR "%s(%d):[%lu, %lu]"
+#define PDESCR(descr)                                                   \
+        cl_lock_mode_name((descr)->cld_mode), (descr)->cld_mode,        \
+        (descr)->cld_start, (descr)->cld_end
+
+const char *cl_lock_mode_name(const enum cl_lock_mode mode);
+
+/**
+ * Lock state-machine states.
+ *
+ * \htmlonly
+ * <pre>
+ *
+ * Possible state transitions:
+ *
+ *              +------------------>NEW
+ *              |                    |
+ *              |                    | cl_enqueue_try()
+ *              |                    |
+ *              |    cl_unuse_try()  V
+ *              |  +--------------QUEUING (*)
+ *              |  |                 |
+ *              |  |                 | cl_enqueue_try()
+ *              |  |                 |
+ *              |  | cl_unuse_try()  V
+ *    sub-lock  |  +-------------ENQUEUED (*)
+ *    canceled  |  |                 |
+ *              |  |                 | cl_wait_try()
+ *              |  |                 |
+ *              |  |                (R)
+ *              |  |                 |
+ *              |  |                 V
+ *              |  |                HELD<---------+
+ *              |  |                 |            |
+ *              |  |                 |            |
+ *              |  |  cl_unuse_try() |            |
+ *              |  |                 |            |
+ *              |  |                 V            | cached
+ *              |  +------------>UNLOCKING (*)    | lock found
+ *              |                    |            |
+ *              |     cl_unuse_try() |            |
+ *              |                    |            |
+ *              |                    |            | cl_use_try()
+ *              |                    V            |
+ *              +------------------CACHED---------+
+ *                                   |
+ *                                  (C)
+ *                                   |
+ *                                   V
+ *                                FREEING
+ *
+ * Legend:
+ *
+ *         In states marked with (*) transition to the same state (i.e., a loop
+ *         in the diagram) is possible.
+ *
+ *         (R) is the point where Receive call-back is invoked: it allows layers
+ *         to handle arrival of lock reply.
+ *
+ *         (C) is the point where Cancellation call-back is invoked.
+ *
+ *         Transition to FREEING state is possible from any other state in the
+ *         diagram in case of unrecoverable error.
+ * </pre>
+ * \endhtmlonly
+ *
+ * These states are for individual cl_lock object. Top-lock and its sub-locks
+ * can be in the different states. Another way to say this is that we have
+ * nested state-machines.
+ *
+ * Separate QUEUING and ENQUEUED states are needed to support non-blocking
+ * operation for locks with multiple sub-locks. Imagine lock on a file F, that
+ * intersects 3 stripes S0, S1, and S2. To enqueue F client has to send
+ * enqueue to S0, wait for its completion, then send enqueue for S1, wait for
+ * its completion and at last enqueue lock for S2, and wait for its
+ * completion. In that case, top-lock is in QUEUING state while S0, S1 are
+ * handled, and is in ENQUEUED state after enqueue to S2 has been sent (note
+ * that in this case, sub-locks move from state to state, and top-lock remains
+ * in the same state).
+ *
+ * Separate UNLOCKING state is needed to maintain an invariant that in HELD
+ * state lock is immediately ready for use.
+ */
+enum cl_lock_state {
+        /**
+         * Lock that wasn't yet enqueued
+         */
+        CLS_NEW,
+        /**
+         * Enqueue is in progress, blocking for some intermediate interaction
+         * with the other side.
+         */
+        CLS_QUEUING,
+        /**
+         * Lock is fully enqueued, waiting for server to reply when it is
+         * granted.
+         */
+        CLS_ENQUEUED,
+        /**
+         * Lock granted, actively used by some IO.
+         */
+        CLS_HELD,
+        /**
+         * Lock is in the transition from CLS_HELD to CLS_CACHED. Lock is in
+         * this state only while cl_unuse() is executing against it.
+         */
+        CLS_UNLOCKING,
+        /**
+         * Lock granted, not used.
+         */
+        CLS_CACHED,
+        /**
+         * Lock is being destroyed.
+         */
+        CLS_FREEING,
+        CLS_NR
+};
+
+enum cl_lock_flags {
+        /**
+         * lock has been cancelled. This flag is never cleared once set (by
+         * cl_lock_cancel0()).
+         */
+        CLF_CANCELLED  = 1 << 0,
+        /** cancellation is pending for this lock. */
+        CLF_CANCELPEND = 1 << 1,
+        /** destruction is pending for this lock. */
+        CLF_DOOMED     = 1 << 2,
+        /** State update is pending. */
+        CLF_STATE      = 1 << 3
+};
+
+/**
+ * Lock closure.
+ *
+ * Lock closure is a collection of locks (both top-locks and sub-locks) that
+ * might be updated in a result of an operation on a certain lock (which lock
+ * this is a closure of).
+ *
+ * Closures are needed to guarantee dead-lock freedom in the presence of
+ *
+ *     - nested state-machines (top-lock state-machine composed of sub-lock
+ *       state-machines), and
+ *
+ *     - shared sub-locks.
+ *
+ * Specifically, many operations, such as lock enqueue, wait, unlock,
+ * etc. start from a top-lock, and then operate on a sub-locks of this
+ * top-lock, holding a top-lock mutex. When sub-lock state changes as a result
+ * of such operation, this change has to be propagated to all top-locks that
+ * share this sub-lock. Obviously, no natural lock ordering (e.g.,
+ * top-to-bottom or bottom-to-top) captures this scenario, so try-locking has
+ * to be used. Lock closure systematizes this try-and-repeat logic.
+ */
+struct cl_lock_closure {
+        /**
+         * Lock that is mutexed when closure construction is started. When
+         * closure in is `wait' mode (cl_lock_closure::clc_wait), mutex on
+         * origin is released before waiting.
+         */
+        struct cl_lock   *clc_origin;
+        /**
+         * List of enclosed locks, so far. Locks are linked here through
+         * cl_lock::cll_inclosure.
+         */
+        struct list_head  clc_list;
+        /**
+         * True iff closure is in a `wait' mode. This determines what
+         * cl_lock_enclosure() does when a lock L to be added to the closure
+         * is currently mutexed by some other thread.
+         *
+         * If cl_lock_closure::clc_wait is not set, then closure construction
+         * fails with CLO_REPEAT immediately.
+         *
+         * In wait mode, cl_lock_enclosure() waits until next attempt to build
+         * a closure might succeed. To this end it releases an origin mutex
+         * (cl_lock_closure::clc_origin), that has to be the only lock mutex
+         * owned by the current thread, and then waits on L mutex (by grabbing
+         * it and immediately releasing), before returning CLO_REPEAT to the
+         * caller.
+         */
+        int               clc_wait;
+        /** Number of locks in the closure. */
+        int               clc_nr;
+};
+
+/**
+ * Layered client lock.
+ */
+struct cl_lock {
+        /** Reference counter. */
+        atomic_t              cll_ref;
+        /** List of slices. Immutable after creation. */
+        struct list_head      cll_layers;
+        /**
+         * Linkage into cl_lock::cll_descr::cld_obj::coh_locks list. Protected
+         * by cl_lock::cll_descr::cld_obj::coh_lock_guard.
+         */
+        struct list_head      cll_linkage;
+        /**
+         * Parameters of this lock. Protected by
+         * cl_lock::cll_descr::cld_obj::coh_lock_guard nested within
+         * cl_lock::cll_guard. Modified only on lock creation and in
+         * cl_lock_modify().
+         */
+        struct cl_lock_descr  cll_descr;
+        /** Protected by cl_lock::cll_guard. */
+        enum cl_lock_state    cll_state;
+        /** signals state changes. */
+        cfs_waitq_t           cll_wq;
+        /**
+         * Recursive lock, most fields in cl_lock{} are protected by this.
+         *
+         * Locking rules: this mutex is never held across network
+         * communication, except when lock is being canceled.
+         *
+         * Lock ordering: a mutex of a sub-lock is taken first, then a mutex
+         * on a top-lock. Other direction is implemented through a
+         * try-lock-repeat loop. Mutices of unrelated locks can be taken only
+         * by try-locking.
+         *
+         * \see osc_lock_enqueue_wait(), lov_lock_cancel(), lov_sublock_wait().
+         */
+        struct mutex          cll_guard;
+        cfs_task_t           *cll_guarder;
+        int                   cll_depth;
+
+        int                   cll_error;
+        /**
+         * Number of holds on a lock. A hold prevents a lock from being
+         * canceled and destroyed. Protected by cl_lock::cll_guard.
+         *
+         * \see cl_lock_hold(), cl_lock_unhold(), cl_lock_release()
+         */
+        int                   cll_holds;
+         /**
+          * Number of lock users. Valid in cl_lock_state::CLS_HELD state
+          * only. Lock user pins lock in CLS_HELD state. Protected by
+          * cl_lock::cll_guard.
+          *
+          * \see cl_wait(), cl_unuse().
+          */
+        int                   cll_users;
+        /**
+         * Flag bit-mask. Values from enum cl_lock_flags. Updates are
+         * protected by cl_lock::cll_guard.
+         */
+        unsigned long         cll_flags;
+        /**
+         * A linkage into a list of locks in a closure.
+         *
+         * \see cl_lock_closure
+         */
+        struct list_head      cll_inclosure;
+        /**
+         * A list of references to this lock, for debugging.
+         */
+        struct lu_ref         cll_reference;
+        /**
+         * A list of holds on this lock, for debugging.
+         */
+        struct lu_ref         cll_holders;
+        /**
+         * A reference for cl_lock::cll_descr::cld_obj. For debugging.
+         */
+        struct lu_ref_link   *cll_obj_ref;
+#ifdef CONFIG_LOCKDEP
+        /* "dep_map" name is assumed by lockdep.h macros. */
+        struct lockdep_map    dep_map;
+#endif
+};
+
+/**
+ * Per-layer part of cl_lock
+ *
+ * \see ccc_lock, lov_lock, lovsub_lock, osc_lock
+ */
+struct cl_lock_slice {
+        struct cl_lock                  *cls_lock;
+        /** Object slice corresponding to this lock slice. Immutable after
+         * creation. */
+        struct cl_object                *cls_obj;
+        const struct cl_lock_operations *cls_ops;
+        /** Linkage into cl_lock::cll_layers. Immutable after creation. */
+        struct list_head                 cls_linkage;
+};
+
+/**
+ * Possible (non-error) return values of ->clo_{enqueue,wait,unlock}().
+ *
+ * NOTE: lov_subresult() depends on ordering here.
+ */
+enum cl_lock_transition {
+        /** operation cannot be completed immediately. Wait for state change. */
+        CLO_WAIT   = 1,
+        /** operation had to release lock mutex, restart. */
+        CLO_REPEAT = 2
+};
+
+/**
+ *
+ * \see vvp_lock_ops, lov_lock_ops, lovsub_lock_ops, osc_lock_ops
+ */
+struct cl_lock_operations {
+        /**
+         * \name statemachine
+         *
+         * State machine transitions. These 3 methods are called to transfer
+         * lock from one state to another, as described in the commentary
+         * above enum #cl_lock_state.
+         *
+         * \retval 0          this layer has nothing more to do to before
+         *                       transition to the target state happens;
+         *
+         * \retval CLO_REPEAT method had to release and re-acquire cl_lock
+         *                    mutex, repeat invocation of transition method
+         *                    across all layers;
+         *
+         * \retval CLO_WAIT   this layer cannot move to the target state
+         *                    immediately, as it has to wait for certain event
+         *                    (e.g., the communication with the server). It
+         *                    is guaranteed, that when the state transfer
+         *                    becomes possible, cl_lock::cll_wq wait-queue
+         *                    is signaled. Caller can wait for this event by
+         *                    calling cl_lock_state_wait();
+         *
+         * \retval -ve        failure, abort state transition, move the lock
+         *                    into cl_lock_state::CLS_FREEING state, and set
+         *                    cl_lock::cll_error.
+         *
+         * Once all layers voted to agree to transition (by returning 0), lock
+         * is moved into corresponding target state. All state transition
+         * methods are optional.
+         */
+        /** @{ */
+        /**
+         * Attempts to enqueue the lock. Called top-to-bottom.
+         *
+         * \see ccc_lock_enqueue(), lov_lock_enqueue(), lovsub_lock_enqueue(),
+         * \see osc_lock_enqueue()
+         */
+        int  (*clo_enqueue)(const struct lu_env *env,
+                            const struct cl_lock_slice *slice,
+                            struct cl_io *io, __u32 enqflags);
+        /**
+         * Attempts to wait for enqueue result. Called top-to-bottom.
+         *
+         * \see ccc_lock_wait(), lov_lock_wait(), osc_lock_wait()
+         */
+        int  (*clo_wait)(const struct lu_env *env,
+                         const struct cl_lock_slice *slice);
+        /**
+         * Attempts to unlock the lock. Called bottom-to-top. In addition to
+         * usual return values of lock state-machine methods, this can return
+         * -ESTALE to indicate that lock cannot be returned to the cache, and
+         * has to be re-initialized.
+         *
+         * \see ccc_lock_unlock(), lov_lock_unlock(), osc_lock_unlock()
+         */
+        int  (*clo_unuse)(const struct lu_env *env,
+                          const struct cl_lock_slice *slice);
+        /**
+         * Notifies layer that cached lock is started being used.
+         *
+         * \pre lock->cll_state == CLS_CACHED
+         *
+         * \see lov_lock_use(), osc_lock_use()
+         */
+        int  (*clo_use)(const struct lu_env *env,
+                        const struct cl_lock_slice *slice);
+        /** @} statemachine */
+        /**
+         * A method invoked when lock state is changed (as a result of state
+         * transition). This is used, for example, to track when the state of
+         * a sub-lock changes, to propagate this change to the corresponding
+         * top-lock. Optional
+         *
+         * \see lovsub_lock_state()
+         */
+        void (*clo_state)(const struct lu_env *env,
+                          const struct cl_lock_slice *slice,
+                          enum cl_lock_state st);
+        /**
+         * Returns true, iff given lock is suitable for the given io, idea
+         * being, that there are certain "unsafe" locks, e.g., ones acquired
+         * for O_APPEND writes, that we don't want to re-use for a normal
+         * write, to avoid the danger of cascading evictions. Optional. Runs
+         * under cl_object_header::coh_lock_guard.
+         *
+         * XXX this should take more information about lock needed by
+         * io. Probably lock description or something similar.
+         *
+         * \see lov_fits_into()
+         */
+        int (*clo_fits_into)(const struct lu_env *env,
+                             const struct cl_lock_slice *slice,
+                             const struct cl_lock_descr *need,
+                             const struct cl_io *io);
+        /**
+         * \name ast
+         * Asynchronous System Traps. All of then are optional, all are
+         * executed bottom-to-top.
+         */
+        /** @{ */
+
+        /**
+         * Cancellation callback. Cancel a lock voluntarily, or under
+         * the request of server.
+         */
+        void (*clo_cancel)(const struct lu_env *env,
+                           const struct cl_lock_slice *slice);
+        /**
+         * Lock weighting ast. Executed to estimate how precious this lock
+         * is. The sum of results across all layers is used to determine
+         * whether lock worth keeping in cache given present memory usage.
+         *
+         * \see osc_lock_weigh(), vvp_lock_weigh(), lovsub_lock_weigh().
+         */
+        unsigned long (*clo_weigh)(const struct lu_env *env,
+                                   const struct cl_lock_slice *slice);
+        /** @} ast */
+
+        /**
+         * \see lovsub_lock_closure()
+         */
+        int (*clo_closure)(const struct lu_env *env,
+                           const struct cl_lock_slice *slice,
+                           struct cl_lock_closure *closure);
+        /**
+         * Executed top-to-bottom when lock description changes (e.g., as a
+         * result of server granting more generous lock than was requested).
+         *
+         * \see lovsub_lock_modify()
+         */
+        int (*clo_modify)(const struct lu_env *env,
+                          const struct cl_lock_slice *slice,
+                          const struct cl_lock_descr *updated);
+        /**
+         * Notifies layers (bottom-to-top) that lock is going to be
+         * destroyed. Responsibility of layers is to prevent new references on
+         * this lock from being acquired once this method returns.
+         *
+         * This can be called multiple times due to the races.
+         *
+         * \see cl_lock_delete()
+         * \see osc_lock_delete(), lovsub_lock_delete()
+         */
+        void (*clo_delete)(const struct lu_env *env,
+                           const struct cl_lock_slice *slice);
+        /**
+         * Destructor. Frees resources and the slice.
+         *
+         * \see ccc_lock_fini(), lov_lock_fini(), lovsub_lock_fini(),
+         * \see osc_lock_fini()
+         */
+        void (*clo_fini)(const struct lu_env *env, struct cl_lock_slice *slice);
+        /**
+         * Optional debugging helper. Prints given lock slice.
+         */
+        int (*clo_print)(const struct lu_env *env,
+                         void *cookie, lu_printer_t p,
+                         const struct cl_lock_slice *slice);
+};
+
+#define CL_LOCK_DEBUG(mask, env, lock, format, ...)                     \
+do {                                                                    \
+        static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask);              \
+                                                                        \
+        if (cdebug_show(mask, DEBUG_SUBSYSTEM)) {                       \
+                cl_lock_print(env, &__info, lu_cdebug_printer, lock);   \
+                CDEBUG(mask, format , ## __VA_ARGS__);                  \
+        }                                                               \
+} while (0)
+
+/** @} cl_lock */
+
+/** \addtogroup cl_page_list cl_page_list
+ * Page list used to perform collective operations on a group of pages.
+ *
+ * Pages are added to the list one by one. cl_page_list acquires a reference
+ * for every page in it. Page list is used to perform collective operations on
+ * pages:
+ *
+ *     - submit pages for an immediate transfer,
+ *
+ *     - own pages on behalf of certain io (waiting for each page in turn),
+ *
+ *     - discard pages.
+ *
+ * When list is finalized, it releases references on all pages it still has.
+ *
+ * \todo XXX concurrency control.
+ *
+ * @{
+ */
+struct cl_page_list {
+        unsigned         pl_nr;
+        struct list_head pl_pages;
+        cfs_task_t      *pl_owner;
+};
+
+/** \addtogroup cl_page_list cl_page_list
+ * A 2-queue of pages. A convenience data-type for common use case, 2-queue
+ * contains an incoming page list and an outgoing page list.
+ */
+struct cl_2queue {
+        struct cl_page_list c2_qin;
+        struct cl_page_list c2_qout;
+};
+
+/** @} cl_page_list */
+
+/** \addtogroup cl_io cl_io
+ * @{ */
+/** \struct cl_io
+ * I/O
+ *
+ * cl_io represents a high level I/O activity like
+ * read(2)/write(2)/truncate(2) system call, or cancellation of an extent
+ * lock.
+ *
+ * cl_io is a layered object, much like cl_{object,page,lock} but with one
+ * important distinction. We want to minimize number of calls to the allocator
+ * in the fast path, e.g., in the case of read(2) when everything is cached:
+ * client already owns the lock over region being read, and data are cached
+ * due to read-ahead. To avoid allocation of cl_io layers in such situations,
+ * per-layer io state is stored in the session, associated with the io, see
+ * struct {vvp,lov,osc}_io for example. Sessions allocation is amortized
+ * by using free-lists, see cl_env_get().
+ *
+ * There is a small predefined number of possible io types, enumerated in enum
+ * cl_io_type.
+ *
+ * cl_io is a state machine, that can be advanced concurrently by the multiple
+ * threads. It is up to these threads to control the concurrency and,
+ * specifically, to detect when io is done, and its state can be safely
+ * released.
+ *
+ * For read/write io overall execution plan is as following:
+ *
+ *     (0) initialize io state through all layers;
+ *
+ *     (1) loop: prepare chunk of work to do
+ *
+ *     (2) call all layers to collect locks they need to process current chunk
+ *
+ *     (3) sort all locks to avoid dead-locks, and acquire them
+ *
+ *     (4) process the chunk: call per-page methods
+ *         (cl_io_operations::cio_read_page() for read,
+ *         cl_io_operations::cio_prepare_write(),
+ *         cl_io_operations::cio_commit_write() for write)
+ *
+ *     (5) release locks
+ *
+ *     (6) repeat loop.
+ *
+ * To implement the "parallel IO mode", lov layer creates sub-io's (lazily to
+ * address allocation efficiency issues mentioned above), and returns with the
+ * special error condition from per-page method when current sub-io has to
+ * block. This causes io loop to be repeated, and lov switches to the next
+ * sub-io in its cl_io_operations::cio_iter_init() implementation.
+ */
+
+/** IO types */
+enum cl_io_type {
+        /** read system call */
+        CIT_READ,
+        /** write system call */
+        CIT_WRITE,
+        /** truncate system call */
+        CIT_TRUNC,
+        /**
+         * page fault handling
+         */
+        CIT_FAULT,
+        /**
+         * Miscellaneous io. This is used for occasional io activity that
+         * doesn't fit into other types. Currently this is used for:
+         *
+         *     - cancellation of an extent lock. This io exists as a context
+         *     to write dirty pages from under the lock being canceled back
+         *     to the server;
+         *
+         *     - VM induced page write-out. An io context for writing page out
+         *     for memory cleansing;
+         *
+         *     - glimpse. An io context to acquire glimpse lock.
+         *
+         * CIT_MISC io is used simply as a context in which locks and pages
+         * are manipulated. Such io has no internal "process", that is,
+         * cl_io_loop() is never called for it.
+         */
+        CIT_MISC,
+        CIT_OP_NR
+};
+
+/**
+ * States of cl_io state machine
+ */
+enum cl_io_state {
+        /** Not initialized. */
+        CIS_ZERO,
+        /** Initialized. */
+        CIS_INIT,
+        /** IO iteration started. */
+        CIS_IT_STARTED,
+        /** Locks taken. */
+        CIS_LOCKED,
+        /** Actual IO is in progress. */
+        CIS_IO_GOING,
+        /** IO for the current iteration finished. */
+        CIS_IO_FINISHED,
+        /** Locks released. */
+        CIS_UNLOCKED,
+        /** Iteration completed. */
+        CIS_IT_ENDED,
+        /** cl_io finalized. */
+        CIS_FINI
+};
+
+/**
+ * IO state private for a layer.
+ *
+ * This is usually embedded into layer session data, rather than allocated
+ * dynamically.
+ *
+ * \see vvp_io, lov_io, osc_io, ccc_io
+ */
+struct cl_io_slice {
+        struct cl_io                  *cis_io;
+        /** corresponding object slice. Immutable after creation. */
+        struct cl_object              *cis_obj;
+        /** io operations. Immutable after creation. */
+        const struct cl_io_operations *cis_iop;
+        /**
+         * linkage into a list of all slices for a given cl_io, hanging off
+         * cl_io::ci_layers. Immutable after creation.
+         */
+        struct list_head               cis_linkage;
+};
+
+
+/**
+ * Per-layer io operations.
+ * \see vvp_io_ops, lov_io_ops, lovsub_io_ops, osc_io_ops
+ */
+struct cl_io_operations {
+        /**
+         * Vector of io state transition methods for every io type.
+         *
+         * \see cl_page_operations::io
+         */
+        struct {
+                /**
+                 * Prepare io iteration at a given layer.
+                 *
+                 * Called top-to-bottom at the beginning of each iteration of
+                 * "io loop" (if it makes sense for this type of io). Here
+                 * layer selects what work it will do during this iteration.
+                 *
+                 * \see cl_io_operations::cio_iter_fini()
+                 */
+                int (*cio_iter_init) (const struct lu_env *env,
+                                      const struct cl_io_slice *slice);
+                /**
+                 * Finalize io iteration.
+                 *
+                 * Called bottom-to-top at the end of each iteration of "io
+                 * loop". Here layers can decide whether IO has to be
+                 * continued.
+                 *
+                 * \see cl_io_operations::cio_iter_init()
+                 */
+                void (*cio_iter_fini) (const struct lu_env *env,
+                                       const struct cl_io_slice *slice);
+                /**
+                 * Collect locks for the current iteration of io.
+                 *
+                 * Called top-to-bottom to collect all locks necessary for
+                 * this iteration. This methods shouldn't actually enqueue
+                 * anything, instead it should post a lock through
+                 * cl_io_lock_add(). Once all locks are collected, they are
+                 * sorted and enqueued in the proper order.
+                 */
+                int  (*cio_lock) (const struct lu_env *env,
+                                  const struct cl_io_slice *slice);
+                /**
+                 * Finalize unlocking.
+                 *
+                 * Called bottom-to-top to finish layer specific unlocking
+                 * functionality, after generic code released all locks
+                 * acquired by cl_io_operations::cio_lock().
+                 */
+                void  (*cio_unlock)(const struct lu_env *env,
+                                    const struct cl_io_slice *slice);
+                /**
+                 * Start io iteration.
+                 *
+                 * Once all locks are acquired, called top-to-bottom to
+                 * commence actual IO. In the current implementation,
+                 * top-level vvp_io_{read,write}_start() does all the work
+                 * synchronously by calling generic_file_*(), so other layers
+                 * are called when everything is done.
+                 */
+                int  (*cio_start)(const struct lu_env *env,
+                                  const struct cl_io_slice *slice);
+                /**
+                 * Called top-to-bottom at the end of io loop. Here layer
+                 * might wait for an unfinished asynchronous io.
+                 */
+                void (*cio_end)  (const struct lu_env *env,
+                                  const struct cl_io_slice *slice);
+                /**
+                 * Called bottom-to-top to notify layers that read/write IO
+                 * iteration finished, with \a nob bytes transferred.
+                 */
+                void (*cio_advance)(const struct lu_env *env,
+                                    const struct cl_io_slice *slice,
+                                    size_t nob);
+                /**
+                 * Called once per io, bottom-to-top to release io resources.
+                 */
+                void (*cio_fini) (const struct lu_env *env,
+                                  const struct cl_io_slice *slice);
+        } op[CIT_OP_NR];
+        struct {
+                /**
+                 * Submit pages from \a queue->c2_qin for IO, and move
+                 * successfully submitted pages into \a queue->c2_qout. Return
+                 * non-zero if failed to submit even the single page. If
+                 * submission failed after some pages were moved into \a
+                 * queue->c2_qout, completion callback with non-zero ioret is
+                 * executed on them.
+                 */
+                int  (*cio_submit)(const struct lu_env *env,
+                                   const struct cl_io_slice *slice,
+                                   enum cl_req_type crt,
+                                   struct cl_2queue *queue);
+        } req_op[CRT_NR];
+        /**
+         * Read missing page.
+         *
+         * Called by a top-level cl_io_operations::op[CIT_READ]::cio_start()
+         * method, when it hits not-up-to-date page in the range. Optional.
+         *
+         * \pre io->ci_type == CIT_READ
+         */
+        int (*cio_read_page)(const struct lu_env *env,
+                             const struct cl_io_slice *slice,
+                             const struct cl_page_slice *page);
+        /**
+         * Prepare write of a \a page. Called bottom-to-top by a top-level
+         * cl_io_operations::op[CIT_WRITE]::cio_start() to prepare page for
+         * get data from user-level buffer.
+         *
+         * \pre io->ci_type == CIT_WRITE
+         *
+         * \see vvp_io_prepare_write(), lov_io_prepare_write(),
+         * osc_io_prepare_write().
+         */
+        int (*cio_prepare_write)(const struct lu_env *env,
+                                 const struct cl_io_slice *slice,
+                                 const struct cl_page_slice *page,
+                                 unsigned from, unsigned to);
+        /**
+         *
+         * \pre io->ci_type == CIT_WRITE
+         *
+         * \see vvp_io_commit_write(), lov_io_commit_write(),
+         * osc_io_commit_write().
+         */
+        int (*cio_commit_write)(const struct lu_env *env,
+                                const struct cl_io_slice *slice,
+                                const struct cl_page_slice *page,
+                                unsigned from, unsigned to);
+        /**
+         * Optional debugging helper. Print given io slice.
+         */
+        int (*cio_print)(const struct lu_env *env, void *cookie,
+                         lu_printer_t p, const struct cl_io_slice *slice);
+};
+
+/**
+ * Flags to lock enqueue procedure.
+ * \ingroup cl_lock
+ */
+enum cl_enq_flags {
+        /**
+         * instruct server to not block, if conflicting lock is found. Instead
+         * -EWOULDBLOCK is returned immediately.
+         */
+        CEF_NONBLOCK     = 0x00000001,
+        /**
+         * take lock asynchronously (out of order), as it cannot
+         * deadlock. This is for LDLM_FL_HAS_INTENT locks used for glimpsing.
+         */
+        CEF_ASYNC        = 0x00000002,
+        /**
+         * tell the server to instruct (though a flag in the blocking ast) an
+         * owner of the conflicting lock, that it can drop dirty pages
+         * protected by this lock, without sending them to the server.
+         */
+        CEF_DISCARD_DATA = 0x00000004
+};
+
+/**
+ * Link between lock and io. Intermediate structure is needed, because the
+ * same lock can be part of multiple io's simultaneously.
+ */
+struct cl_io_lock_link {
+        /** linkage into one of cl_lockset lists. */
+        struct list_head     cill_linkage;
+        struct cl_lock_descr cill_descr;
+        struct cl_lock      *cill_lock;
+        /**
+         * flags to enqueue lock for this IO. A combination of bit-flags from
+         * enum cl_enq_flags.
+         */
+        __u32                cill_enq_flags;
+        /** optional destructor */
+        void               (*cill_fini)(const struct lu_env *env,
+                                        struct cl_io_lock_link *link);
+};
+
+/**
+ * Lock-set represents a collection of locks, that io needs at a
+ * time. Generally speaking, client tries to avoid holding multiple locks when
+ * possible, because
+ *
+ *      - holding extent locks over multiple ost's introduces the danger of
+ *        "cascading timeouts";
+ *
+ *      - holding multiple locks over the same ost is still dead-lock prone,
+ *        see comment in osc_lock_enqueue(),
+ *
+ * but there are certain situations where this is unavoidable:
+ *
+ *      - O_APPEND writes have to take [0, EOF] lock for correctness;
+ *
+ *      - truncate has to take [new-size, EOF] lock for correctness;
+ *
+ *      - SNS has to take locks across full stripe for correctness;
+ *
+ *      - in the case when user level buffer, supplied to {read,write}(file0),
+ *        is a part of a memory mapped lustre file, client has to take a dlm
+ *        locks on file0, and all files that back up the buffer (or a part of
+ *        the buffer, that is being processed in the current chunk, in any
+ *        case, there are situations where at least 2 locks are necessary).
+ *
+ * In such cases we at least try to take locks in the same consistent
+ * order. To this end, all locks are first collected, then sorted, and then
+ * enqueued.
+ */
+struct cl_lockset {
+        /** locks to be acquired. */
+        struct list_head cls_todo;
+        /** locks currently being processed. */
+        struct list_head cls_curr;
+        /** locks acquired. */
+        struct list_head cls_done;
+};
+
+/**
+ * Lock requirements(demand) for IO. It should be cl_io_lock_req,
+ * but 'req' is always to be thought as 'request' :-)
+ */
+enum cl_io_lock_dmd {
+        /** Always lock data (e.g., O_APPEND). */
+        CILR_MANDATORY = 0,
+        /** Layers are free to decide between local and global locking. */
+        CILR_MAYBE,
+        /** Never lock: there is no cache (e.g., liblustre). */
+        CILR_NEVER
+};
+
+struct cl_io_rw_common {
+        loff_t      crw_pos;
+        size_t      crw_count;
+        int         crw_nonblock;
+};
+
+/**
+ * State for io.
+ *
+ * cl_io is shared by all threads participating in this IO (in current
+ * implementation only one thread advances IO, but parallel IO design and
+ * concurrent copy_*_user() require multiple threads acting on the same IO. It
+ * is up to these threads to serialize their activities, including updates to
+ * mutable cl_io fields.
+ */
+struct cl_io {
+        /** type of this IO. Immutable after creation. */
+        enum cl_io_type                ci_type;
+        /** current state of cl_io state machine. */
+        enum cl_io_state               ci_state;
+        /** main object this io is against. Immutable after creation. */
+        struct cl_object              *ci_obj;
+        /**
+         * Upper layer io, of which this io is a part of. Immutable after
+         * creation.
+         */
+        struct cl_io                  *ci_parent;
+        /** List of slices. Immutable after creation. */
+        struct list_head               ci_layers;
+        /** list of locks (to be) acquired by this io. */
+        struct cl_lockset              ci_lockset;
+        /** lock requirements, this is just a help info for sublayers. */
+        enum cl_io_lock_dmd            ci_lockreq;
+        union {
+                struct cl_rd_io {
+                        struct cl_io_rw_common rd;
+                        int                    rd_is_sendfile;
+                } ci_rd;
+                struct cl_wr_io {
+                        struct cl_io_rw_common wr;
+                        int                    wr_append;
+                } ci_wr;
+                struct cl_io_rw_common ci_rw;
+                struct cl_truncate_io {
+                        /** new size to which file is truncated */
+                        size_t           tr_size;
+                        struct obd_capa *tr_capa;
+                } ci_truncate;
+                struct cl_fault_io {
+                        /** page index within file. */
+                        pgoff_t         ft_index;
+                        /** bytes valid byte on a faulted page. */
+                        int             ft_nob;
+                        /** writable page? */
+                        int             ft_writable;
+                        /** page of an executable? */
+                        int             ft_executable;
+                        /** resulting page */
+                        struct cl_page *ft_page;
+                } ci_fault;
+        } u;
+        struct cl_2queue     ci_queue;
+        size_t               ci_nob;
+        int                  ci_result;
+        int                  ci_continue;
+        /**
+         * Number of pages owned by this IO. For invariant checking.
+         */
+        unsigned             ci_owned_nr;
+};
+
+/** @} cl_io */
+
+/** \addtogroup cl_req cl_req
+ * @{ */
+/** \struct cl_req
+ * Transfer.
+ *
+ * There are two possible modes of transfer initiation on the client:
+ *
+ *     - immediate transfer: this is started when a high level io wants a page
+ *       or a collection of pages to be transferred right away. Examples:
+ *       read-ahead, synchronous read in the case of non-page aligned write,
+ *       page write-out as a part of extent lock cancellation, page write-out
+ *       as a part of memory cleansing. Immediate transfer can be both
+ *       cl_req_type::CRT_READ and cl_req_type::CRT_WRITE;
+ *
+ *     - opportunistic transfer (cl_req_type::CRT_WRITE only), that happens
+ *       when io wants to transfer a page to the server some time later, when
+ *       it can be done efficiently. Example: pages dirtied by the write(2)
+ *       path.
+ *
+ * In any case, transfer takes place in the form of a cl_req, which is a
+ * representation for a network RPC.
+ *
+ * Pages queued for an opportunistic transfer are cached until it is decided
+ * that efficient RPC can be composed of them. This decision is made by "a
+ * req-formation engine", currently implemented as a part of osc
+ * layer. Req-formation depends on many factors: the size of the resulting
+ * RPC, whether or not multi-object RPCs are supported by the server,
+ * max-rpc-in-flight limitations, size of the dirty cache, etc.
+ *
+ * For the immediate transfer io submits a cl_page_list, that req-formation
+ * engine slices into cl_req's, possibly adding cached pages to some of
+ * the resulting req's.
+ *
+ * Whenever a page from cl_page_list is added to a newly constructed req, its
+ * cl_page_operations::cpo_prep() layer methods are called. At that moment,
+ * page state is atomically changed from cl_page_state::CPS_OWNED to
+ * cl_page_state::CPS_PAGEOUT or cl_page_state::CPS_PAGEIN, cl_page::cp_owner
+ * is zeroed, and cl_page::cp_req is set to the
+ * req. cl_page_operations::cpo_prep() method at the particular layer might
+ * return -EALREADY to indicate that it does not need to submit this page
+ * at all. This is possible, for example, if page, submitted for read,
+ * became up-to-date in the meantime; and for write, the page don't have
+ * dirty bit marked. \see cl_io_submit_rw()
+ *
+ * Whenever a cached page is added to a newly constructed req, its
+ * cl_page_operations::cpo_make_ready() layer methods are called. At that
+ * moment, page state is atomically changed from cl_page_state::CPS_CACHED to
+ * cl_page_state::CPS_PAGEOUT, and cl_page::cp_req is set to
+ * req. cl_page_operations::cpo_make_ready() method at the particular layer
+ * might return -EAGAIN to indicate that this page is not eligible for the
+ * transfer right now.
+ *
+ * FUTURE
+ *
+ * Plan is to divide transfers into "priority bands" (indicated when
+ * submitting cl_page_list, and queuing a page for the opportunistic transfer)
+ * and allow glueing of cached pages to immediate transfers only within single
+ * band. This would make high priority transfers (like lock cancellation or
+ * memory pressure induced write-out) really high priority.
+ *
+ */
+
+/**
+ * Per-transfer attributes.
+ */
+struct cl_req_attr {
+        /** Generic attributes for the server consumption. */
+        struct obdo     *cra_oa;
+        /** Capability. */
+        struct obd_capa *cra_capa;
+};
+
+/**
+ * Transfer request operations definable at every layer.
+ *
+ * Concurrency: transfer formation engine synchronizes calls to all transfer
+ * methods.
+ */
+struct cl_req_operations {
+        /**
+         * Invoked top-to-bottom by cl_req_prep() when transfer formation is
+         * complete (all pages are added).
+         *
+         * \see osc_req_prep()
+         */
+        int  (*cro_prep)(const struct lu_env *env,
+                         const struct cl_req_slice *slice);
+        /**
+         * Called top-to-bottom to fill in \a oa fields. This is called twice
+         * with different flags, see bug 10150 and osc_build_req().
+         *
+         * \param obj an object from cl_req which attributes are to be set in
+         *            \a oa.
+         *
+         * \param oa struct obdo where attributes are placed
+         *
+         * \param flags \a oa fields to be filled.
+         */
+        void (*cro_attr_set)(const struct lu_env *env,
+                             const struct cl_req_slice *slice,
+                             const struct cl_object *obj,
+                             struct cl_req_attr *attr, obd_valid flags);
+        /**
+         * Called top-to-bottom from cl_req_completion() to notify layers that
+         * transfer completed. Has to free all state allocated by
+         * cl_device_operations::cdo_req_init().
+         */
+        void (*cro_completion)(const struct lu_env *env,
+                               const struct cl_req_slice *slice, int ioret);
+};
+
+/**
+ * A per-object state that (potentially multi-object) transfer request keeps.
+ */
+struct cl_req_obj {
+        /** object itself */
+        struct cl_object   *ro_obj;
+        /** reference to cl_req_obj::ro_obj. For debugging. */
+        struct lu_ref_link *ro_obj_ref;
+        /* something else? Number of pages for a given object? */
+};
+
+/**
+ * Transfer request.
+ *
+ * Transfer requests are not reference counted, because IO sub-system owns
+ * them exclusively and knows when to free them.
+ *
+ * Life cycle.
+ *
+ * cl_req is created by cl_req_alloc() that calls
+ * cl_device_operations::cdo_req_init() device methods to allocate per-req
+ * state in every layer.
+ *
+ * Then pages are added (cl_req_page_add()), req keeps track of all objects it
+ * contains pages for.
+ *
+ * Once all pages were collected, cl_page_operations::cpo_prep() method is
+ * called top-to-bottom. At that point layers can modify req, let it pass, or
+ * deny it completely. This is to support things like SNS that have transfer
+ * ordering requirements invisible to the individual req-formation engine.
+ *
+ * On transfer completion (or transfer timeout, or failure to initiate the
+ * transfer of an allocated req), cl_req_operations::cro_completion() method
+ * is called, after execution of cl_page_operations::cpo_completion() of all
+ * req's pages.
+ */
+struct cl_req {
+        enum cl_req_type    crq_type;
+        /** A list of pages being transfered */
+        struct list_head    crq_pages;
+        /** Number of pages in cl_req::crq_pages */
+        unsigned            crq_nrpages;
+        /** An array of objects which pages are in ->crq_pages */
+        struct cl_req_obj  *crq_o;
+        /** Number of elements in cl_req::crq_objs[] */
+        unsigned            crq_nrobjs;
+        struct list_head    crq_layers;
+};
+
+/**
+ * Per-layer state for request.
+ */
+struct cl_req_slice {
+        struct cl_req    *crs_req;
+        struct cl_device *crs_dev;
+        struct list_head  crs_linkage;
+        const struct cl_req_operations *crs_ops;
+};
+
+/* @} cl_req */
+
+/**
+ * Stats for a generic cache (similar to inode, lu_object, etc. caches).
+ */
+struct cache_stats {
+        const char    *cs_name;
+        /** how many entities were created at all */
+        atomic_t       cs_created;
+        /** how many cache lookups were performed */
+        atomic_t       cs_lookup;
+        /** how many times cache lookup resulted in a hit */
+        atomic_t       cs_hit;
+        /** how many entities are in the cache right now */
+        atomic_t       cs_total;
+        /** how many entities in the cache are actively used (and cannot be
+         * evicted) right now */
+        atomic_t       cs_busy;
+};
+
+/** These are not exported so far */
+void cache_stats_init (struct cache_stats *cs, const char *name);
+int  cache_stats_print(const struct cache_stats *cs,
+                       char *page, int count, int header);
+
+/**
+ * Client-side site. This represents particular client stack. "Global"
+ * variables should (directly or indirectly) be added here to allow multiple
+ * clients to co-exist in the single address space.
+ */
+struct cl_site {
+        struct lu_site        cs_lu;
+        /**
+         * Statistical counters. Atomics do not scale, something better like
+         * per-cpu counters is needed.
+         *
+         * These are exported as /proc/fs/lustre/llite/.../site
+         *
+         * When interpreting keep in mind that both sub-locks (and sub-pages)
+         * and top-locks (and top-pages) are accounted here.
+         */
+        struct cache_stats    cs_pages;
+        struct cache_stats    cs_locks;
+        atomic_t              cs_pages_state[CPS_NR];
+        atomic_t              cs_locks_state[CLS_NR];
+};
+
+int  cl_site_init (struct cl_site *s, struct cl_device *top);
+void cl_site_fini (struct cl_site *s);
+void cl_stack_fini(const struct lu_env *env, struct cl_device *cl);
+
+/**
+ * Output client site statistical counters into a buffer. Suitable for
+ * ll_rd_*()-style functions.
+ */
+int cl_site_stats_print(const struct cl_site *s, char *page, int count);
+
+/**
+ * \name helpers
+ *
+ * Type conversion and accessory functions.
+ */
+/** @{ */
+
+static inline struct cl_site *lu2cl_site(const struct lu_site *site)
+{
+        return container_of(site, struct cl_site, cs_lu);
+}
+
+static inline int lu_device_is_cl(const struct lu_device *d)
+{
+        return d->ld_type->ldt_tags & LU_DEVICE_CL;
+}
+
+static inline struct cl_device *lu2cl_dev(const struct lu_device *d)
+{
+        LASSERT(d == NULL || IS_ERR(d) || lu_device_is_cl(d));
+        return container_of0(d, struct cl_device, cd_lu_dev);
+}
+
+static inline struct lu_device *cl2lu_dev(struct cl_device *d)
+{
+        return &d->cd_lu_dev;
+}
+
+static inline struct cl_object *lu2cl(const struct lu_object *o)
+{
+        LASSERT(o == NULL || IS_ERR(o) || lu_device_is_cl(o->lo_dev));
+        return container_of0(o, struct cl_object, co_lu);
+}
+
+static inline const struct cl_object_conf *
+lu2cl_conf(const struct lu_object_conf *conf)
+{
+        return container_of0(conf, struct cl_object_conf, coc_lu);
+}
+
+static inline struct cl_object *cl_object_next(const struct cl_object *obj)
+{
+        return obj ? lu2cl(lu_object_next(&obj->co_lu)) : NULL;
+}
+
+static inline struct cl_device *cl_object_device(const struct cl_object *o)
+{
+        LASSERT(o == NULL || IS_ERR(o) || lu_device_is_cl(o->co_lu.lo_dev));
+        return container_of0(o->co_lu.lo_dev, struct cl_device, cd_lu_dev);
+}
+
+static inline struct cl_object_header *luh2coh(const struct lu_object_header *h)
+{
+        return container_of0(h, struct cl_object_header, coh_lu);
+}
+
+static inline struct cl_site *cl_object_site(const struct cl_object *obj)
+{
+        return lu2cl_site(obj->co_lu.lo_dev->ld_site);
+}
+
+static inline
+struct cl_object_header *cl_object_header(const struct cl_object *obj)
+{
+        return luh2coh(obj->co_lu.lo_header);
+}
+
+static inline int cl_device_init(struct cl_device *d, struct lu_device_type *t)
+{
+        return lu_device_init(&d->cd_lu_dev, t);
+}
+
+static inline void cl_device_fini(struct cl_device *d)
+{
+        lu_device_fini(&d->cd_lu_dev);
+}
+
+void cl_page_slice_add(struct cl_page *page, struct cl_page_slice *slice,
+                       struct cl_object *obj,
+                       const struct cl_page_operations *ops);
+void cl_lock_slice_add(struct cl_lock *lock, struct cl_lock_slice *slice,
+                       struct cl_object *obj,
+                       const struct cl_lock_operations *ops);
+void cl_io_slice_add(struct cl_io *io, struct cl_io_slice *slice,
+                     struct cl_object *obj, const struct cl_io_operations *ops);
+void cl_req_slice_add(struct cl_req *req, struct cl_req_slice *slice,
+                      struct cl_device *dev,
+                      const struct cl_req_operations *ops);
+/** @} helpers */
+
+/** \defgroup cl_object cl_object
+ * @{ */
+struct cl_object *cl_object_top (struct cl_object *o);
+struct cl_object *cl_object_find(const struct lu_env *env, struct cl_device *cd,
+                                 const struct lu_fid *fid,
+                                 const struct cl_object_conf *c);
+
+int  cl_object_header_init(struct cl_object_header *h);
+void cl_object_header_fini(struct cl_object_header *h);
+void cl_object_put        (const struct lu_env *env, struct cl_object *o);
+void cl_object_get        (struct cl_object *o);
+void cl_object_attr_lock  (struct cl_object *o);
+void cl_object_attr_unlock(struct cl_object *o);
+int  cl_object_attr_get   (const struct lu_env *env, struct cl_object *obj,
+                           struct cl_attr *attr);
+int  cl_object_attr_set   (const struct lu_env *env, struct cl_object *obj,
+                           const struct cl_attr *attr, unsigned valid);
+int  cl_object_glimpse    (const struct lu_env *env, struct cl_object *obj,
+                           struct ost_lvb *lvb);
+int  cl_conf_set          (const struct lu_env *env, struct cl_object *obj,
+                           const struct cl_object_conf *conf);
+void cl_object_prune      (const struct lu_env *env, struct cl_object *obj);
+void cl_object_kill       (const struct lu_env *env, struct cl_object *obj);
+
+/**
+ * Returns true, iff \a o0 and \a o1 are slices of the same object.
+ */
+static inline int cl_object_same(struct cl_object *o0, struct cl_object *o1)
+{
+        return cl_object_header(o0) == cl_object_header(o1);
+}
+
+/** @} cl_object */
+
+/** \defgroup cl_page cl_page
+ * @{ */
+struct cl_page       *cl_page_lookup(struct cl_object_header *hdr,
+                                     pgoff_t index);
+void                  cl_page_gang_lookup(const struct lu_env *env,
+                                          struct cl_object *obj,
+                                          struct cl_io *io,
+                                          pgoff_t start, pgoff_t end,
+                                          struct cl_page_list *plist);
+struct cl_page *cl_page_find        (const struct lu_env *env,
+                                     struct cl_object *obj,
+                                     pgoff_t idx, struct page *vmpage,
+                                     enum cl_page_type type);
+void            cl_page_get         (struct cl_page *page);
+void            cl_page_put         (const struct lu_env *env,
+                                     struct cl_page *page);
+void            cl_page_print       (const struct lu_env *env, void *cookie,
+                                     lu_printer_t printer,
+                                     const struct cl_page *pg);
+void            cl_page_header_print(const struct lu_env *env, void *cookie,
+                                     lu_printer_t printer,
+                                     const struct cl_page *pg);
+cfs_page_t     *cl_page_vmpage      (const struct lu_env *env,
+                                     struct cl_page *page);
+struct cl_page *cl_vmpage_page      (cfs_page_t *vmpage, struct cl_object *obj);
+struct cl_page *cl_page_top         (struct cl_page *page);
+int             cl_is_page          (const void *addr);
+
+const struct cl_page_slice *cl_page_at(const struct cl_page *page,
+                                       const struct lu_device_type *dtype);
+
+/**
+ * \name ownership
+ *
+ * Functions dealing with the ownership of page by io.
+ */
+/** @{ */
+
+int  cl_page_own        (const struct lu_env *env,
+                         struct cl_io *io, struct cl_page *page);
+void cl_page_assume     (const struct lu_env *env,
+                         struct cl_io *io, struct cl_page *page);
+void cl_page_unassume   (const struct lu_env *env,
+                         struct cl_io *io, struct cl_page *pg);
+void cl_page_disown     (const struct lu_env *env,
+                         struct cl_io *io, struct cl_page *page);
+int  cl_page_is_owned   (const struct cl_page *pg, const struct cl_io *io);
+
+/** @} ownership */
+
+/**
+ * \name transfer
+ *
+ * Functions dealing with the preparation of a page for a transfer, and
+ * tracking transfer state.
+ */
+/** @{ */
+int  cl_page_prep       (const struct lu_env *env, struct cl_io *io,
+                         struct cl_page *pg, enum cl_req_type crt);
+void cl_page_completion (const struct lu_env *env,
+                         struct cl_page *pg, enum cl_req_type crt, int ioret);
+int  cl_page_make_ready (const struct lu_env *env, struct cl_page *pg,
+                         enum cl_req_type crt);
+int  cl_page_cache_add  (const struct lu_env *env, struct cl_io *io,
+                         struct cl_page *pg, enum cl_req_type crt);
+void cl_page_clip       (const struct lu_env *env, struct cl_page *pg,
+                         int from, int to);
+int  cl_page_cancel     (const struct lu_env *env, struct cl_page *page);
+
+/** @} transfer */
+
+
+/**
+ * \name helper routines
+ * Functions to discard, delete and export a cl_page.
+ */
+/** @{ */
+void    cl_page_discard      (const struct lu_env *env, struct cl_io *io,
+                              struct cl_page *pg);
+void    cl_page_delete       (const struct lu_env *env, struct cl_page *pg);
+int     cl_page_unmap        (const struct lu_env *env, struct cl_io *io,
+                              struct cl_page *pg);
+int     cl_page_is_vmlocked  (const struct lu_env *env,
+                              const struct cl_page *pg);
+void    cl_page_export       (const struct lu_env *env, struct cl_page *pg);
+int     cl_page_is_under_lock(const struct lu_env *env, struct cl_io *io,
+                              struct cl_page *page);
+loff_t  cl_offset            (const struct cl_object *obj, pgoff_t idx);
+pgoff_t cl_index             (const struct cl_object *obj, loff_t offset);
+int     cl_page_size         (const struct cl_object *obj);
+int     cl_pages_prune       (const struct lu_env *env, struct cl_object *obj);
+
+void cl_lock_print      (const struct lu_env *env, void *cookie,
+                         lu_printer_t printer, const struct cl_lock *lock);
+void cl_lock_descr_print(const struct lu_env *env, void *cookie,
+                         lu_printer_t printer,
+                         const struct cl_lock_descr *descr);
+/* @} helper */
+
+/** @} cl_page */
+
+/** \defgroup cl_lock cl_lock
+ * @{ */
+
+struct cl_lock *cl_lock_hold(const struct lu_env *env, const struct cl_io *io,
+                             const struct cl_lock_descr *need,
+                             const char *scope, const void *source);
+struct cl_lock *cl_lock_peek(const struct lu_env *env, const struct cl_io *io,
+                             const struct cl_lock_descr *need,
+                             const char *scope, const void *source);
+struct cl_lock *cl_lock_request(const struct lu_env *env, struct cl_io *io,
+                                const struct cl_lock_descr *need,
+                                __u32 enqflags,
+                                const char *scope, const void *source);
+struct cl_lock *cl_lock_at_page(const struct lu_env *env, struct cl_object *obj,
+                                struct cl_page *page, struct cl_lock *except,
+                                int pending, int canceld);
+
+const struct cl_lock_slice *cl_lock_at(const struct cl_lock *lock,
+                                       const struct lu_device_type *dtype);
+
+void  cl_lock_get       (struct cl_lock *lock);
+void  cl_lock_get_trust (struct cl_lock *lock);
+void  cl_lock_put       (const struct lu_env *env, struct cl_lock *lock);
+void  cl_lock_hold_add  (const struct lu_env *env, struct cl_lock *lock,
+                         const char *scope, const void *source);
+void  cl_lock_unhold    (const struct lu_env *env, struct cl_lock *lock,
+                         const char *scope, const void *source);
+void  cl_lock_release   (const struct lu_env *env, struct cl_lock *lock,
+                         const char *scope, const void *source);
+void  cl_lock_user_add  (const struct lu_env *env, struct cl_lock *lock);
+int   cl_lock_user_del  (const struct lu_env *env, struct cl_lock *lock);
+int   cl_lock_compatible(const struct cl_lock *lock1,
+                         const struct cl_lock *lock2);
+
+/** \name statemachine statemachine
+ * Interface to lock state machine consists of 3 parts:
+ *
+ *     - "try" functions that attempt to effect a state transition. If state
+ *     transition is not possible right now (e.g., if it has to wait for some
+ *     asynchronous event to occur), these functions return
+ *     cl_lock_transition::CLO_WAIT.
+ *
+ *     - "non-try" functions that implement synchronous blocking interface on
+ *     top of non-blocking "try" functions. These functions repeatedly call
+ *     corresponding "try" versions, and if state transition is not possible
+ *     immediately, wait for lock state change.
+ *
+ *     - methods from cl_lock_operations, called by "try" functions. Lock can
+ *     be advanced to the target state only when all layers voted that they
+ *     are ready for this transition. "Try" functions call methods under lock
+ *     mutex. If a layer had to release a mutex, it re-acquires it and returns
+ *     cl_lock_transition::CLO_REPEAT, causing "try" function to call all
+ *     layers again.
+ *
+ * TRY              NON-TRY      METHOD                            FINAL STATE
+ *
+ * cl_enqueue_try() cl_enqueue() cl_lock_operations::clo_enqueue() CLS_ENQUEUED
+ *
+ * cl_wait_try()    cl_wait()    cl_lock_operations::clo_wait()    CLS_HELD
+ *
+ * cl_unuse_try()   cl_unuse()   cl_lock_operations::clo_unuse()   CLS_CACHED
+ *
+ * cl_use_try()     NONE         cl_lock_operations::clo_use()     CLS_HELD
+ *
+ * @{ */
+
+int   cl_enqueue    (const struct lu_env *env, struct cl_lock *lock,
+                     struct cl_io *io, __u32 flags);
+int   cl_wait       (const struct lu_env *env, struct cl_lock *lock);
+void  cl_unuse      (const struct lu_env *env, struct cl_lock *lock);
+int   cl_enqueue_try(const struct lu_env *env, struct cl_lock *lock,
+                     struct cl_io *io, __u32 flags);
+int   cl_unuse_try  (const struct lu_env *env, struct cl_lock *lock);
+int   cl_wait_try   (const struct lu_env *env, struct cl_lock *lock);
+int   cl_use_try    (const struct lu_env *env, struct cl_lock *lock);
+/** @} statemachine */
+
+void cl_lock_signal      (const struct lu_env *env, struct cl_lock *lock);
+int  cl_lock_state_wait  (const struct lu_env *env, struct cl_lock *lock);
+void cl_lock_state_set   (const struct lu_env *env, struct cl_lock *lock,
+                          enum cl_lock_state state);
+int  cl_queue_match      (const struct list_head *queue,
+                          const struct cl_lock_descr *need);
+
+void cl_lock_mutex_get  (const struct lu_env *env, struct cl_lock *lock);
+int  cl_lock_mutex_try  (const struct lu_env *env, struct cl_lock *lock);
+void cl_lock_mutex_put  (const struct lu_env *env, struct cl_lock *lock);
+int  cl_lock_is_mutexed (struct cl_lock *lock);
+int  cl_lock_nr_mutexed (const struct lu_env *env);
+int  cl_lock_page_out   (const struct lu_env *env, struct cl_lock *lock,
+                         int discard);
+int  cl_lock_ext_match  (const struct cl_lock_descr *has,
+                         const struct cl_lock_descr *need);
+int  cl_lock_descr_match(const struct cl_lock_descr *has,
+                         const struct cl_lock_descr *need);
+int  cl_lock_mode_match (enum cl_lock_mode has, enum cl_lock_mode need);
+int  cl_lock_modify     (const struct lu_env *env, struct cl_lock *lock,
+                         const struct cl_lock_descr *desc);
+
+void cl_lock_closure_init (const struct lu_env *env,
+                           struct cl_lock_closure *closure,
+                           struct cl_lock *origin, int wait);
+void cl_lock_closure_fini (struct cl_lock_closure *closure);
+int  cl_lock_closure_build(const struct lu_env *env, struct cl_lock *lock,
+                           struct cl_lock_closure *closure);
+void cl_lock_disclosure   (const struct lu_env *env,
+                           struct cl_lock_closure *closure);
+int  cl_lock_enclosure    (const struct lu_env *env, struct cl_lock *lock,
+                           struct cl_lock_closure *closure);
+
+void cl_lock_cancel(const struct lu_env *env, struct cl_lock *lock);
+void cl_lock_delete(const struct lu_env *env, struct cl_lock *lock);
+void cl_lock_error (const struct lu_env *env, struct cl_lock *lock, int error);
+void cl_locks_prune(const struct lu_env *env, struct cl_object *obj, int wait);
+int  cl_is_lock    (const void *addr);
+
+unsigned long cl_lock_weigh(const struct lu_env *env, struct cl_lock *lock);
+
+/** @} cl_lock */
+
+/** \defgroup cl_io cl_io
+ * @{ */
+
+int   cl_io_init         (const struct lu_env *env, struct cl_io *io,
+                          enum cl_io_type iot, struct cl_object *obj);
+int   cl_io_sub_init     (const struct lu_env *env, struct cl_io *io,
+                          enum cl_io_type iot, struct cl_object *obj);
+int   cl_io_rw_init      (const struct lu_env *env, struct cl_io *io,
+                          enum cl_io_type iot, loff_t pos, size_t count);
+int   cl_io_loop         (const struct lu_env *env, struct cl_io *io);
+
+void  cl_io_fini         (const struct lu_env *env, struct cl_io *io);
+int   cl_io_iter_init    (const struct lu_env *env, struct cl_io *io);
+void  cl_io_iter_fini    (const struct lu_env *env, struct cl_io *io);
+int   cl_io_lock         (const struct lu_env *env, struct cl_io *io);
+void  cl_io_unlock       (const struct lu_env *env, struct cl_io *io);
+int   cl_io_start        (const struct lu_env *env, struct cl_io *io);
+void  cl_io_end          (const struct lu_env *env, struct cl_io *io);
+int   cl_io_lock_add     (const struct lu_env *env, struct cl_io *io,
+                          struct cl_io_lock_link *link);
+int   cl_io_lock_alloc_add(const struct lu_env *env, struct cl_io *io,
+                           struct cl_lock_descr *descr);
+int   cl_io_read_page    (const struct lu_env *env, struct cl_io *io,
+                          struct cl_page *page);
+int   cl_io_prepare_write(const struct lu_env *env, struct cl_io *io,
+                          struct cl_page *page, unsigned from, unsigned to);
+int   cl_io_commit_write (const struct lu_env *env, struct cl_io *io,
+                          struct cl_page *page, unsigned from, unsigned to);
+int   cl_io_submit_rw    (const struct lu_env *env, struct cl_io *io,
+                          enum cl_req_type iot, struct cl_2queue *queue);
+void  cl_io_rw_advance   (const struct lu_env *env, struct cl_io *io,
+                          size_t nob);
+int   cl_io_cancel       (const struct lu_env *env, struct cl_io *io,
+                          struct cl_page_list *queue);
+int   cl_io_is_going     (const struct lu_env *env);
+
+/**
+ * True, iff \a io is an O_APPEND write(2).
+ */
+static inline int cl_io_is_append(const struct cl_io *io)
+{
+        return io->ci_type == CIT_WRITE && io->u.ci_wr.wr_append;
+}
+
+int cl_io_is_sendfile(const struct cl_io *io);
+
+struct cl_io *cl_io_top(struct cl_io *io);
+
+void cl_io_print(const struct lu_env *env, void *cookie,
+                 lu_printer_t printer, const struct cl_io *io);
+
+#define CL_IO_SLICE_CLEAN(foo_io, base)                                 \
+do {                                                                    \
+        typeof(foo_io) __foo_io = (foo_io);                             \
+                                                                        \
+        CLASSERT(offsetof(typeof(*__foo_io), base) == 0);               \
+        memset(&__foo_io->base + 1, 0,                                  \
+               (sizeof *__foo_io) - sizeof __foo_io->base);             \
+} while (0)
+
+/** @} cl_io */
+
+/** \defgroup cl_page_list cl_page_list
+ * @{ */
+
+/**
+ * Iterate over pages in a page list.
+ */
+#define cl_page_list_for_each(page, list)                               \
+        list_for_each_entry((page), &(list)->pl_pages, cp_batch)
+
+/**
+ * Iterate over pages in a page list, taking possible removals into account.
+ */
+#define cl_page_list_for_each_safe(page, temp, list)                    \
+        list_for_each_entry_safe((page), (temp), &(list)->pl_pages, cp_batch)
+
+void cl_page_list_init   (struct cl_page_list *plist);
+void cl_page_list_add    (struct cl_page_list *plist, struct cl_page *page);
+void cl_page_list_move   (struct cl_page_list *dst, struct cl_page_list *src,
+                          struct cl_page *page);
+void cl_page_list_splice (struct cl_page_list *list,
+                          struct cl_page_list *head);
+void cl_page_list_del    (const struct lu_env *env,
+                          struct cl_page_list *plist, struct cl_page *page);
+void cl_page_list_disown (const struct lu_env *env,
+                          struct cl_io *io, struct cl_page_list *plist);
+int  cl_page_list_own    (const struct lu_env *env,
+                          struct cl_io *io, struct cl_page_list *plist);
+void cl_page_list_assume (const struct lu_env *env,
+                          struct cl_io *io, struct cl_page_list *plist);
+void cl_page_list_discard(const struct lu_env *env,
+                          struct cl_io *io, struct cl_page_list *plist);
+int  cl_page_list_unmap  (const struct lu_env *env,
+                          struct cl_io *io, struct cl_page_list *plist);
+void cl_page_list_fini   (const struct lu_env *env, struct cl_page_list *plist);
+
+void cl_2queue_init     (struct cl_2queue *queue);
+void cl_2queue_add      (struct cl_2queue *queue, struct cl_page *page);
+void cl_2queue_disown   (const struct lu_env *env,
+                         struct cl_io *io, struct cl_2queue *queue);
+void cl_2queue_assume   (const struct lu_env *env,
+                         struct cl_io *io, struct cl_2queue *queue);
+void cl_2queue_discard  (const struct lu_env *env,
+                         struct cl_io *io, struct cl_2queue *queue);
+void cl_2queue_fini     (const struct lu_env *env, struct cl_2queue *queue);
+void cl_2queue_init_page(struct cl_2queue *queue, struct cl_page *page);
+
+/** @} cl_page_list */
+
+/** \defgroup cl_req cl_req
+ * @{ */
+struct cl_req *cl_req_alloc(const struct lu_env *env, struct cl_page *page,
+                            enum cl_req_type crt, int nr_objects);
+
+void cl_req_page_add  (const struct lu_env *env, struct cl_req *req,
+                       struct cl_page *page);
+void cl_req_page_done (const struct lu_env *env, struct cl_page *page);
+int  cl_req_prep      (const struct lu_env *env, struct cl_req *req);
+void cl_req_attr_set  (const struct lu_env *env, struct cl_req *req,
+                       struct cl_req_attr *attr, obd_valid flags);
+void cl_req_completion(const struct lu_env *env, struct cl_req *req, int ioret);
+
+/** \defgroup cl_sync_io cl_sync_io
+ * @{ */
+
+/**
+ * Anchor for synchronous transfer. This is allocated on a stack by thread
+ * doing synchronous transfer, and a pointer to this structure is set up in
+ * every page submitted for transfer. Transfer completion routine updates
+ * anchor and wakes up waiting thread when transfer is complete.
+ */
+struct cl_sync_io {
+        /** number of pages yet to be transferred. */
+        atomic_t             csi_sync_nr;
+        /** completion to be signaled when transfer is complete. */
+        struct completion    csi_sync_completion;
+        /** error code. */
+        int                  csi_sync_rc;
+};
+
+void cl_sync_io_init(struct cl_sync_io *anchor, int nrpages);
+int  cl_sync_io_wait(const struct lu_env *env, struct cl_io *io,
+                     struct cl_page_list *queue, struct cl_sync_io *anchor);
+void cl_sync_io_note(struct cl_sync_io *anchor, int ioret);
+
+/** @} cl_sync_io */
+
+/** @} cl_req */
+
+/** \defgroup cl_env cl_env
+ *
+ * lu_env handling for a client.
+ *
+ * lu_env is an environment within which lustre code executes. Its major part
+ * is lu_context---a fast memory allocation mechanism that is used to conserve
+ * precious kernel stack space. Originally lu_env was designed for a server,
+ * where
+ *
+ *     - there is a (mostly) fixed number of threads, and
+ *
+ *     - call chains have no non-lustre portions inserted between lustre code.
+ *
+ * On a client both these assumtpion fails, because every user thread can
+ * potentially execute lustre code as part of a system call, and lustre calls
+ * into VFS or MM that call back into lustre.
+ *
+ * To deal with that, cl_env wrapper functions implement the following
+ * optimizations:
+ *
+ *     - allocation and destruction of environment is amortized by caching no
+ *     longer used environments instead of destroying them;
+ *
+ *     - there is a notion of "current" environment, attached to the kernel
+ *     data structure representing current thread (current->journal_info in
+ *     Linux kernel). Top-level lustre code allocates an environment and makes
+ *     it current, then calls into non-lustre code, that in turn calls lustre
+ *     back. Low-level lustre code thus called can fetch environment created
+ *     by the top-level code and reuse it, avoiding additional environment
+ *     allocation.
+ *
+ * \see lu_env, lu_context, lu_context_key
+ * @{ */
+
+struct cl_env_nest {
+        int   cen_refcheck;
+        void *cen_cookie;
+};
+
+struct lu_env *cl_env_peek       (int *refcheck);
+struct lu_env *cl_env_get        (int *refcheck);
+struct lu_env *cl_env_alloc      (int *refcheck, __u32 tags);
+struct lu_env *cl_env_nested_get (struct cl_env_nest *nest);
+void           cl_env_put        (struct lu_env *env, int *refcheck);
+void           cl_env_nested_put (struct cl_env_nest *nest, struct lu_env *env);
+void          *cl_env_reenter    (void);
+void           cl_env_reexit     (void *cookie);
+void           cl_env_implant    (struct lu_env *env, int *refcheck);
+void           cl_env_unplant    (struct lu_env *env, int *refcheck);
+unsigned       cl_env_cache_purge(unsigned nr);
+
+/** @} cl_env */
+
+/*
+ * Misc
+ */
+void cl_attr2lvb(struct ost_lvb *lvb, const struct cl_attr *attr);
+void cl_lvb2attr(struct cl_attr *attr, const struct ost_lvb *lvb);
+
+struct cl_device *cl_type_setup(const struct lu_env *env, struct lu_site *site,
+                                struct lu_device_type *ldt,
+                                struct lu_device *next);
+/** @} clio */
+
+#endif /* _LINUX_CL_OBJECT_H */
index b1fa210..fbbb9ad 100644 (file)
@@ -184,7 +184,7 @@ extern const struct dt_index_features dt_directory_features;
 
 /**
  * This is a general purpose dt allocation hint.
- * It now contains the parent object. 
+ * It now contains the parent object.
  * It can contain any allocation hint in the future.
  */
 struct dt_allocation_hint {
@@ -287,7 +287,7 @@ struct dt_object_operations {
          * postcondition: ergo(result == 0, dt_object_exists(dt));
          */
         int   (*do_create)(const struct lu_env *env, struct dt_object *dt,
-                           struct lu_attr *attr, 
+                           struct lu_attr *attr,
                            struct dt_allocation_hint *hint,
                            struct thandle *th);
 
@@ -414,7 +414,7 @@ struct dt_index_operations {
 };
 
 struct dt_device {
-        struct lu_device             dd_lu_dev;
+        struct lu_device                   dd_lu_dev;
         const struct dt_device_operations *dd_ops;
 
         /**
@@ -422,7 +422,7 @@ struct dt_device {
          * way, because callbacks are supposed to be added/deleted only during
          * single-threaded start-up shut-down procedures.
          */
-        struct list_head             dd_txn_callbacks;
+        struct list_head                   dd_txn_callbacks;
 };
 
 int  dt_device_init(struct dt_device *dev, struct lu_device_type *t);
@@ -440,7 +440,7 @@ static inline struct dt_device * lu2dt_dev(struct lu_device *l)
 }
 
 struct dt_object {
-        struct lu_object             do_lu;
+        struct lu_object                   do_lu;
         const struct dt_object_operations *do_ops;
         const struct dt_body_operations   *do_body_ops;
         const struct dt_index_operations  *do_index_ops;
diff --git a/lustre/include/lclient.h b/lustre/include/lclient.h
new file mode 100644 (file)
index 0000000..dfd7f65
--- /dev/null
@@ -0,0 +1,375 @@
+/* -*- 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * Definitions shared between vvp and liblustre, and other clients in the
+ * future.
+ *
+ *   Author: Oleg Drokin <oleg.drokin@sun.com>
+ *   Author: Nikita Danilov <nikita.danilov@sun.com>
+ */
+
+#ifndef LCLIENT_H
+#define LCLIENT_H
+
+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);
+
+/**
+ * Common IO arguments for various VFS I/O interfaces.
+ */
+struct ccc_io_args {
+        int           cia_is_sendfile;
+#ifndef HAVE_FILE_WRITEV
+        struct kiocb *cia_iocb;
+#endif
+        struct iovec *cia_iov;
+        unsigned long cia_nrsegs;
+        read_actor_t  cia_actor;
+        void         *cia_target;
+};
+
+/**
+ * Locking policy for truncate.
+ */
+enum ccc_trunc_lock_type {
+        /** Locking is done by server */
+        TRUNC_NOLOCK,
+        /** Extent lock is enqueued */
+        TRUNC_EXTENT,
+        /** Existing local extent lock is used */
+        TRUNC_MATCH
+};
+
+/**
+ * IO state private to vvp or slp layers.
+ */
+struct ccc_io {
+        /** super class */
+        struct cl_io_slice     cui_cl;
+        struct cl_io_lock_link cui_link;
+        /**
+         * I/O vector information to or from which read/write is going.
+         */
+        struct iovec *cui_iov;
+        unsigned long cui_nrsegs;
+        /**
+         * Total iov count for left IO.
+         */
+        unsigned long cui_tot_nrsegs;
+        /**
+         * Old length for iov that was truncated partially.
+         */
+        size_t cui_iov_olen;
+        /**
+         * Total size for the left IO.
+         */
+        size_t cui_tot_count;
+
+        union {
+                struct {
+                        int                      cui_locks_released;
+                        enum ccc_trunc_lock_type cui_local_lock;
+                } trunc;
+        } u;
+        /**
+         * True iff io is processing glimpse right now.
+         */
+        int                  cui_glimpse;
+        /**
+         * File descriptor against which IO is done.
+         */
+        struct ll_file_data *cui_fd;
+#ifndef HAVE_FILE_WRITEV
+        struct kiocb *cui_iocb;
+#endif
+};
+
+extern struct lu_context_key ccc_key;
+extern struct lu_context_key ccc_session_key;
+
+struct ccc_thread_info {
+        struct cl_lock_descr cti_descr;
+        struct cl_io         cti_io;
+        struct cl_sync_io    cti_sync_io;
+        struct cl_attr       cti_attr;
+};
+
+static inline struct ccc_thread_info *ccc_env_info(const struct lu_env *env)
+{
+        struct ccc_thread_info      *info;
+
+        info = lu_context_key_get(&env->le_ctx, &ccc_key);
+        LASSERT(info != NULL);
+        return info;
+}
+
+struct ccc_session {
+        struct ccc_io cs_ios;
+};
+
+static inline struct ccc_session *ccc_env_session(const struct lu_env *env)
+{
+        struct ccc_session *ses;
+
+        ses = lu_context_key_get(env->le_ses, &ccc_session_key);
+        LASSERT(ses != NULL);
+        return ses;
+}
+
+static inline struct ccc_io *ccc_env_io(const struct lu_env *env)
+{
+        return &ccc_env_session(env)->cs_ios;
+}
+
+/**
+ * ccc-private object state.
+ */
+struct ccc_object {
+        struct cl_object_header cob_header;
+        struct cl_object        cob_cl;
+        struct inode           *cob_inode;
+
+        /**
+         * A list of dirty pages pending IO in the cache. Used by
+         * SOM. Protected by ll_inode_info::lli_lock.
+         *
+         * \see ccc_page::cpg_pending_linkage
+         */
+        struct list_head        cob_pending_list;
+
+        /**
+         * Access this counter is protected by inode->i_sem. Now that
+         * the lifetime of transient pages must be covered by inode sem,
+         * we don't need to hold any lock..
+         */
+        int                     cob_transient_pages;
+        /**
+         * Number of outstanding mmaps on this file.
+         *
+         * \see ll_vm_open(), ll_vm_close().
+         */
+        atomic_t                cob_mmap_cnt;
+};
+
+/**
+ * ccc-private page state.
+ */
+struct ccc_page {
+        struct cl_page_slice cpg_cl;
+        int                  cpg_defer_uptodate;
+        int                  cpg_ra_used;
+        int                  cpg_write_queued;
+        /**
+         * Non-empty iff this page is already counted in
+         * ccc_object::cob_pending_list. Protected by
+         * ccc_object::cob_pending_guard. This list is only used as a flag,
+         * that is, never iterated through, only checked for list_empty(), but
+         * having a list is useful for debugging.
+         */
+        struct list_head     cpg_pending_linkage;
+        /** VM page */
+        cfs_page_t          *cpg_page;
+        struct cl_sync_io   *cpg_sync_io;
+        /**
+         * checksum for paranoid I/O debugging enabled by
+         * ENABLE_LLITE_CHECKSUM configuration option.
+         *
+         * XXX This cannot be implemented reliably because checksum cannot be
+         * updated from ->set_page_dirty() that is called without page VM
+         * lock.
+         */
+        __u32                cpg_checksum;
+};
+
+static inline struct ccc_page *cl2ccc_page(const struct cl_page_slice *slice)
+{
+        return container_of(slice, struct ccc_page, cpg_cl);
+}
+
+struct cl_page    *ccc_vmpage_page_transient(cfs_page_t *vmpage);
+
+struct ccc_device {
+        struct cl_device    cdv_cl;
+        struct super_block *cdv_sb;
+        struct cl_device   *cdv_next;
+};
+
+struct ccc_lock {
+        struct cl_lock_slice clk_cl;
+};
+
+struct ccc_req {
+        struct cl_req_slice  crq_cl;
+};
+
+void *ccc_key_init        (const struct lu_context *ctx,
+                           struct lu_context_key *key);
+void  ccc_key_fini        (const struct lu_context *ctx,
+                           struct lu_context_key *key, void *data);
+void *ccc_session_key_init(const struct lu_context *ctx,
+                           struct lu_context_key *key);
+void  ccc_session_key_fini(const struct lu_context *ctx,
+                           struct lu_context_key *key, void *data);
+
+int              ccc_device_init  (const struct lu_env *env,
+                                   struct lu_device *d,
+                                   const char *name, struct lu_device *next);
+struct lu_device *ccc_device_fini (const struct lu_env *env,
+                                   struct lu_device *d);
+struct lu_device *ccc_device_alloc(const struct lu_env *env,
+                                   struct lu_device_type *t,
+                                   struct lustre_cfg *cfg,
+                                   const struct lu_device_operations *luops,
+                                   const struct cl_device_operations *clops);
+struct lu_device *ccc_device_free (const struct lu_env *env,
+                                   struct lu_device *d);
+struct lu_object *ccc_object_alloc(const struct lu_env *env,
+                                   const struct lu_object_header *hdr,
+                                   struct lu_device *dev,
+                                   const struct cl_object_operations *clops,
+                                   const struct lu_object_operations *luops);
+
+int ccc_req_init(const struct lu_env *env, struct cl_device *dev,
+                 struct cl_req *req);
+void ccc_umount(const struct lu_env *env, struct cl_device *dev);
+int ccc_global_init(struct lu_device_type *device_type);
+void ccc_global_fini(struct lu_device_type *device_type);
+int ccc_object_init0(const struct lu_env *env,struct ccc_object *vob,
+                     const struct cl_object_conf *conf);
+int ccc_object_init(const struct lu_env *env, struct lu_object *obj,
+                    const struct lu_object_conf *conf);
+void ccc_object_free(const struct lu_env *env, struct lu_object *obj);
+int ccc_lock_init(const struct lu_env *env, struct cl_object *obj,
+                  struct cl_lock *lock, const struct cl_io *io,
+                  const struct cl_lock_operations *lkops);
+int ccc_attr_set(const struct lu_env *env, struct cl_object *obj,
+                 const struct cl_attr *attr, unsigned valid);
+int ccc_object_glimpse(const struct lu_env *env,
+                       const struct cl_object *obj, struct ost_lvb *lvb);
+int ccc_conf_set(const struct lu_env *env, struct cl_object *obj,
+                 const struct cl_object_conf *conf);
+cfs_page_t *ccc_page_vmpage(const struct lu_env *env,
+                            const struct cl_page_slice *slice);
+int ccc_page_is_under_lock(const struct lu_env *env,
+                           const struct cl_page_slice *slice, struct cl_io *io);
+int ccc_fail(const struct lu_env *env, const struct cl_page_slice *slice);
+void ccc_transient_page_verify(const struct cl_page *page);
+void ccc_transient_page_own(const struct lu_env *env,
+                            const struct cl_page_slice *slice,
+                            struct cl_io *io);
+void ccc_transient_page_assume(const struct lu_env *env,
+                               const struct cl_page_slice *slice,
+                               struct cl_io *io);
+void ccc_transient_page_unassume(const struct lu_env *env,
+                                 const struct cl_page_slice *slice,
+                                 struct cl_io *io);
+void ccc_transient_page_disown(const struct lu_env *env,
+                               const struct cl_page_slice *slice,
+                               struct cl_io *io);
+void ccc_transient_page_discard(const struct lu_env *env,
+                                const struct cl_page_slice *slice,
+                                struct cl_io *io);
+int ccc_transient_page_prep(const struct lu_env *env,
+                            const struct cl_page_slice *slice,
+                            struct cl_io *io);
+void ccc_lock_fini(const struct lu_env *env,struct cl_lock_slice *slice);
+int ccc_lock_enqueue(const struct lu_env *env,const struct cl_lock_slice *slice,
+                     struct cl_io *io, __u32 enqflags);
+int ccc_lock_unuse(const struct lu_env *env,const struct cl_lock_slice *slice);
+int ccc_lock_wait(const struct lu_env *env,const struct cl_lock_slice *slice);
+int ccc_lock_fits_into(const struct lu_env *env,
+                       const struct cl_lock_slice *slice,
+                       const struct cl_lock_descr *need,
+                       const struct cl_io *io);
+void ccc_lock_state(const struct lu_env *env,
+                    const struct cl_lock_slice *slice,
+                    enum cl_lock_state state);
+
+void ccc_io_fini(const struct lu_env *env, const struct cl_io_slice *ios);
+int ccc_io_one_lock_index(const struct lu_env *env, struct cl_io *io,
+                          __u32 enqflags, enum cl_lock_mode mode,
+                          pgoff_t start, pgoff_t end);
+int ccc_io_one_lock(const struct lu_env *env, struct cl_io *io,
+                    __u32 enqflags, enum cl_lock_mode mode,
+                    loff_t start, loff_t end);
+void ccc_io_end(const struct lu_env *env, const struct cl_io_slice *ios);
+int ccc_prep_size(const struct lu_env *env, struct cl_object *obj,
+                  struct cl_io *io, loff_t pos, int vfslock);
+void ccc_req_completion(const struct lu_env *env,
+                        const struct cl_req_slice *slice, int ioret);
+void ccc_req_attr_set(const struct lu_env *env,const struct cl_req_slice *slice,
+                      const struct cl_object *obj,
+                      struct cl_req_attr *oa, obd_valid flags);
+
+struct lu_device   *ccc2lu_dev      (struct ccc_device *vdv);
+struct lu_object   *ccc2lu          (struct ccc_object *vob);
+struct ccc_device  *lu2ccc_dev      (const struct lu_device *d);
+struct ccc_device  *cl2ccc_dev      (const struct cl_device *d);
+struct ccc_object  *lu2ccc          (const struct lu_object *obj);
+struct ccc_object  *cl2ccc          (const struct cl_object *obj);
+struct ccc_lock    *cl2ccc_lock     (const struct cl_lock_slice *slice);
+struct ccc_io      *cl2ccc_io       (const struct lu_env *env,
+                                     const struct cl_io_slice *slice);
+struct ccc_req     *cl2ccc_req      (const struct cl_req_slice *slice);
+cfs_page_t         *cl2vm_page      (const struct cl_page_slice *slice);
+struct inode       *ccc_object_inode(const struct cl_object *obj);
+struct ccc_object  *cl_inode2ccc    (struct inode *inode);
+
+int cl_setattr_do_truncate(struct inode *inode, loff_t size,
+                           struct obd_capa *capa);
+int cl_setattr_ost(struct inode *inode, struct obd_capa *capa);
+
+struct cl_page *ccc_vmpage_page_transient(cfs_page_t *vmpage);
+int ccc_object_invariant(const struct cl_object *obj);
+int cl_inode_init(struct inode *inode, struct lustre_md *md);
+void cl_inode_fini(struct inode *inode);
+int cl_local_size(struct inode *inode);
+
+#ifdef INVARIANT_CHECK
+# define CLOBINVRNT(env, clob, expr)                                    \
+  do {                                                                  \
+          if (unlikely(!(expr))) {                                      \
+                  LU_OBJECT_DEBUG(D_ERROR, (env), &(clob)->co_lu, #expr "\n"); \
+                  LINVRNT(0);                                           \
+          }                                                             \
+  } while (0)
+#else /* !INVARIANT_CHECK */
+# define CLOBINVRNT(env, clob, expr)                                    \
+        ((void)sizeof(env), (void)sizeof(clob), (void)sizeof !!(expr))
+#endif /* !INVARIANT_CHECK */
+
+
+#endif /*LCLIENT_H */
index 13b2e26..09bf725 100644 (file)
@@ -71,7 +71,7 @@ typedef unsigned short umode_t;
 /*
  * The inter_module_get implementation is specific to liblustre, so this needs
  * to stay here for now.
- */ 
+ */
 static inline void inter_module_put(void *a)
 {
         return;
@@ -251,6 +251,7 @@ struct task_struct {
         int ngroups;
         gid_t *groups;
         __u32 cap_effective;
+        void *journal_info;
 };
 
 
@@ -378,7 +379,7 @@ void *liblustre_register_wait_callback(const char *name,
 void liblustre_deregister_wait_callback(void *notifier);
 int liblustre_wait_event(int timeout);
 
-void *liblustre_register_idle_callback(const char *name, 
+void *liblustre_register_idle_callback(const char *name,
                                        int (*fn)(void *arg), void *arg);
 void liblustre_deregister_idle_callback(void *notifier);
 void liblustre_wait_idle(void);
@@ -484,10 +485,10 @@ void posix_acl_release(struct posix_acl *acl)
 }
 
 #ifdef LIBLUSTRE_POSIX_ACL
-# ifndef posix_acl_xattr_entry 
+# ifndef posix_acl_xattr_entry
 #  define posix_acl_xattr_entry xattr_acl_entry
 # endif
-# ifndef posix_acl_xattr_header 
+# ifndef posix_acl_xattr_header
 #  define posix_acl_xattr_header xattr_acl_header
 # endif
 # ifndef posix_acl_xattr_size
index f5d07a5..713341e 100644 (file)
 
 # define LUSTRE_POSIX_ACL_MAX_ENTRIES   (32)
 
+#ifdef __KERNEL__
 # define LUSTRE_POSIX_ACL_MAX_SIZE   XATTR_ACL_SIZE
+#else
+# define LUSTRE_POSIX_ACL_MAX_SIZE   0
+#endif
 
 # else /* CONFIG_FS_POSIX_ACL */
 # define LUSTRE_POSIX_ACL_MAX_SIZE      0
index 4bd7b0c..7f3f0da 100644 (file)
@@ -339,7 +339,7 @@ int filemap_fdatawrite_range(struct address_space *mapping,
 #endif
 
 #ifdef HAVE_VFS_KERN_MOUNT
-static inline 
+static inline
 struct vfsmount *
 ll_kern_mount(const char *fstype, int flags, const char *name, void *data)
 {
@@ -355,45 +355,6 @@ ll_kern_mount(const char *fstype, int flags, const char *name, void *data)
 #define ll_kern_mount(fstype, flags, name, data) do_kern_mount((fstype), (flags), (name), (data))
 #endif
 
-#ifndef HAVE_GENERIC_FILE_READ
-static inline
-ssize_t
-generic_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
-{
-        struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
-        struct kiocb kiocb;
-        ssize_t ret;
-
-        init_sync_kiocb(&kiocb, filp);
-        kiocb.ki_pos = *ppos;
-        kiocb.ki_left = len;
-
-        ret = generic_file_aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
-        *ppos = kiocb.ki_pos;
-        return ret;
-}
-#endif
-
-#ifndef HAVE_GENERIC_FILE_WRITE
-static inline
-ssize_t
-generic_file_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
-{
-        struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
-        struct kiocb kiocb;
-        ssize_t ret;
-
-        init_sync_kiocb(&kiocb, filp);
-        kiocb.ki_pos = *ppos;
-        kiocb.ki_left = len;
-
-        ret = generic_file_aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
-        *ppos = kiocb.ki_pos;
-
-        return ret;
-}
-#endif
-
 #ifdef HAVE_STATFS_DENTRY_PARAM
 #define ll_do_statfs(sb, sfs) (sb)->s_op->statfs((sb)->s_root, (sfs))
 #else
@@ -426,7 +387,7 @@ static inline u32 get_sb_time_gran(struct super_block *sb)
 #ifdef HAVE_UNREGISTER_BLKDEV_RETURN_INT
 #define ll_unregister_blkdev(a,b)       unregister_blkdev((a),(b))
 #else
-static inline 
+static inline
 int ll_unregister_blkdev(unsigned int dev, const char *name)
 {
         unregister_blkdev(dev, name);
@@ -542,7 +503,7 @@ struct blkcipher_desc {
 
 extern struct ll_crypto_cipher *ll_crypto_alloc_blkcipher(
                             const char * algname, u32 type, u32 mask);
-static inline 
+static inline
 struct ll_crypto_hash *ll_crypto_alloc_hash(const char *alg, u32 type, u32 mask)
 {
         char        buf[CRYPTO_MAX_ALG_NAME + 1];
@@ -568,10 +529,10 @@ static inline int ll_crypto_hash_update(struct hash_desc *desc,
 {
         struct scatterlist *sl = sg;
         unsigned int        count;
-                /* 
+                /*
                  * This way is very weakness. We must ensure that
                  * the sum of sg[0..i]->length isn't greater than nbytes.
-                 * In the upstream kernel the crypto_hash_update() also 
+                 * In the upstream kernel the crypto_hash_update() also
                  * via the nbytes computed the count of sg[...].
                  * The old style is more safely. but it gone.
                  */
@@ -617,7 +578,7 @@ static inline int ll_crypto_hmac(struct crypto_tfm *tfm,
 #define ll_vfs_mknod(dir,entry,mnt,mode,dev)            \
                 vfs_mknod(dir,entry,mnt,mode,dev)
 #define ll_security_inode_unlink(dir,entry,mnt)         \
-                security_inode_unlink(dir,entry,mnt)     
+                security_inode_unlink(dir,entry,mnt)
 #define ll_vfs_rename(old,old_dir,mnt,new,new_dir,mnt1) \
                 vfs_rename(old,old_dir,mnt,new,new_dir,mnt1)
 #else
@@ -627,7 +588,7 @@ static inline int ll_crypto_hmac(struct crypto_tfm *tfm,
 #define ll_vfs_link(old,mnt,dir,new,mnt1)       vfs_link(old,dir,new)
 #define ll_vfs_unlink(inode,entry,mnt)          vfs_unlink(inode,entry)
 #define ll_vfs_mknod(dir,entry,mnt,mode,dev)    vfs_mknod(dir,entry,mode,dev)
-#define ll_security_inode_unlink(dir,entry,mnt) security_inode_unlink(dir,entry)     
+#define ll_security_inode_unlink(dir,entry,mnt) security_inode_unlink(dir,entry)
 #define ll_vfs_rename(old,old_dir,mnt,new,new_dir,mnt1) \
                 vfs_rename(old,old_dir,new,new_dir)
 #endif
index ccb001d..2e21b08 100644 (file)
 #ifndef AUTOCONF_INCLUDED
 #include <linux/config.h>
 #endif
+#include <linux/seq_file.h>
+#include <linux/module.h>
 #include <linux/autoconf.h>
 #include <linux/slab.h>
 #include <linux/highmem.h>
+#include <linux/swap.h>
 #endif
 #include <libcfs/libcfs.h>
 #include <linux/lustre_compat25.h>
index 9dd557f..9c2f283 100644 (file)
@@ -143,7 +143,7 @@ struct lu_device_operations {
          *  repeatedly, until no new objects are created.
          *
          * \post ergo(!IS_ERR(result), result->lo_dev == d &&
-         *                                      result->lo_ops != NULL);
+         *                             result->lo_ops != NULL);
          */
         struct lu_object *(*ldo_object_alloc)(const struct lu_env *env,
                                               const struct lu_object_header *h,
@@ -177,7 +177,7 @@ typedef int (*lu_printer_t)(const struct lu_env *env,
                             void *cookie, const char *format, ...)
         __attribute__ ((format (printf, 3, 4)));
 
-/*
+/**
  * Operations specific for particular lu_object.
  */
 struct lu_object_operations {
@@ -247,7 +247,7 @@ struct lu_device {
          *
          * \todo XXX which means that atomic_t is probably too small.
          */
-        atomic_t                     ld_ref;
+        atomic_t                           ld_ref;
         /**
          * Pointer to device type. Never modified once set.
          */
@@ -259,11 +259,11 @@ struct lu_device {
         /**
          * Stack this device belongs to.
          */
-        struct lu_site              *ld_site;
-        struct proc_dir_entry       *ld_proc_entry;
+        struct lu_site                    *ld_site;
+        struct proc_dir_entry             *ld_proc_entry;
 
         /** \todo XXX: temporary back pointer into obd. */
-        struct obd_device           *ld_obd;
+        struct obd_device                 *ld_obd;
         /**
          * A list of references to this object, for debugging.
          */
@@ -292,11 +292,11 @@ struct lu_device_type {
         /**
          * Tag bits. Taken from enum lu_device_tag. Never modified once set.
          */
-        __u32                             ldt_tags;
+        __u32                                   ldt_tags;
         /**
          * Name of this class. Unique system-wide. Never modified once set.
          */
-        char                             *ldt_name;
+        char                                   *ldt_name;
         /**
          * Operations for this type.
          */
@@ -304,11 +304,11 @@ struct lu_device_type {
         /**
          * \todo XXX: temporary pointer to associated obd_type.
          */
-        struct obd_type                  *ldt_obd_type;
+        struct obd_type                        *ldt_obd_type;
         /**
          * \todo XXX: temporary: context tags used by obd_*() calls.
          */
-        __u32                             ldt_ctx_tags;
+        __u32                                   ldt_ctx_tags;
         /**
          * Number of existing device type instances.
          */
@@ -437,34 +437,34 @@ enum la_valid {
         LA_BLKSIZE = 1 << 12,
 };
 
-/*
+/**
  * Layer in the layered object.
  */
 struct lu_object {
-        /*
+        /**
          * Header for this object.
          */
-        struct lu_object_header     *lo_header;
-        /*
+        struct lu_object_header           *lo_header;
+        /**
          * Device for this layer.
          */
-        struct lu_device            *lo_dev;
-        /*
+        struct lu_device                  *lo_dev;
+        /**
          * Operations for this object.
          */
         const struct lu_object_operations *lo_ops;
-        /*
+        /**
          * Linkage into list of all layers.
          */
-        struct list_head             lo_linkage;
-        /*
+        struct list_head                   lo_linkage;
+        /**
          * Depth. Top level layer depth is 0.
          */
-        int                          lo_depth;
-        /*
+        int                                lo_depth;
+        /**
          * Flags from enum lu_object_flags.
          */
-        unsigned long                lo_flags;
+        unsigned long                      lo_flags;
         /**
          * Link to the device, for debugging.
          */
@@ -472,7 +472,7 @@ struct lu_object {
 };
 
 enum lu_object_header_flags {
-        /*
+        /**
          * Don't keep this object in cache. Object will be destroyed as soon
          * as last reference to it is released. This flag cannot be cleared
          * once set.
@@ -483,14 +483,14 @@ enum lu_object_header_flags {
 enum lu_object_header_attr {
         LOHA_EXISTS   = 1 << 0,
         LOHA_REMOTE   = 1 << 1,
-        /*
+        /**
          * UNIX file type is stored in S_IFMT bits.
          */
-        LOHA_FT_START = 1 << 12, /* S_IFIFO */
-        LOHA_FT_END   = 1 << 15, /* S_IFREG */
+        LOHA_FT_START = 1 << 12, /**< S_IFIFO */
+        LOHA_FT_END   = 1 << 15, /**< S_IFREG */
 };
 
-/*
+/**
  * "Compound" object, consisting of multiple layers.
  *
  * Compound object with given fid is unique with given lu_site.
@@ -506,33 +506,33 @@ struct lu_object_header {
          * Object flags from enum lu_object_header_flags. Set and checked
          * atomically.
          */
-        unsigned long     loh_flags;
+        unsigned long       loh_flags;
         /**
          * Object reference count. Protected by lu_site::ls_guard.
          */
-        atomic_t          loh_ref;
+        atomic_t            loh_ref;
         /**
          * Fid, uniquely identifying this object.
          */
-        struct lu_fid     loh_fid;
+        struct lu_fid       loh_fid;
         /**
          * Common object attributes, cached for efficiency. From enum
          * lu_object_header_attr.
          */
-        __u32             loh_attr;
+        __u32               loh_attr;
         /**
          * Linkage into per-site hash table. Protected by lu_site::ls_guard.
          */
-        struct hlist_node loh_hash;
+        struct hlist_node   loh_hash;
         /**
          * Linkage into per-site LRU list. Protected by lu_site::ls_guard.
          */
-        struct list_head  loh_lru;
+        struct list_head    loh_lru;
         /**
          * Linkage into list of layers. Never modified once set (except lately
          * during object destruction). No locking is necessary.
          */
-        struct list_head  loh_layers;
+        struct list_head    loh_layers;
         /**
          * A list of references to this object, for debugging.
          */
@@ -608,6 +608,7 @@ struct lu_site {
          * Top-level device for this stack.
          */
         struct lu_device     *ls_top_dev;
+
         /**
          * Wait-queue signaled when an object in this site is ultimately
          * destroyed (lu_object_free()). It is used by lu_object_find() to
@@ -666,10 +667,10 @@ void lu_device_get        (struct lu_device *d);
 void lu_device_put        (struct lu_device *d);
 int  lu_device_init       (struct lu_device *d, struct lu_device_type *t);
 void lu_device_fini       (struct lu_device *d);
-int lu_object_header_init(struct lu_object_header *h);
+int  lu_object_header_init(struct lu_object_header *h);
 void lu_object_header_fini(struct lu_object_header *h);
 int  lu_object_init       (struct lu_object *o,
-                   struct lu_object_header *h, struct lu_device *d);
+                           struct lu_object_header *h, struct lu_device *d);
 void lu_object_fini       (struct lu_object *o);
 void lu_object_add_top    (struct lu_object_header *h, struct lu_object *o);
 void lu_object_add        (struct lu_object *before, struct lu_object *o);
@@ -801,20 +802,20 @@ int lu_cdebug_printer(const struct lu_env *env,
  * Print object description followed by a user-supplied message.
  */
 #define LU_OBJECT_DEBUG(mask, env, object, format, ...)                 \
-({                                                                      \
+do {                                                                    \
         static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask);              \
                                                                         \
         if (cdebug_show(mask, DEBUG_SUBSYSTEM)) {                       \
-        lu_object_print(env, &__info, lu_cdebug_printer, object);       \
-        CDEBUG(mask, format , ## __VA_ARGS__);                          \
+                lu_object_print(env, &__info, lu_cdebug_printer, object); \
+                CDEBUG(mask, format , ## __VA_ARGS__);                  \
         }                                                               \
-})
+} while (0)
 
 /**
  * Print short object description followed by a user-supplied message.
  */
 #define LU_OBJECT_HEADER(mask, env, object, format, ...)                \
-({                                                                      \
+do {                                                                    \
         static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask);              \
                                                                         \
         if (cdebug_show(mask, DEBUG_SUBSYSTEM)) {                       \
@@ -823,10 +824,10 @@ int lu_cdebug_printer(const struct lu_env *env,
                 lu_cdebug_printer(env, &__info, "\n");                  \
                 CDEBUG(mask, format , ## __VA_ARGS__);                  \
         }                                                               \
-})
+} while (0)
 
 void lu_object_print       (const struct lu_env *env, void *cookie,
-                     lu_printer_t printer, const struct lu_object *o);
+                            lu_printer_t printer, const struct lu_object *o);
 void lu_object_header_print(const struct lu_env *env, void *cookie,
                             lu_printer_t printer,
                             const struct lu_object_header *hdr);
@@ -975,6 +976,10 @@ struct lu_context {
          * keys were registered.
          */
         unsigned               lc_version;
+        /**
+         * Debugging cookie.
+         */
+        unsigned               lc_cookie;
 };
 
 /**
@@ -1167,50 +1172,52 @@ void  lu_context_key_revive  (struct lu_context_key *key);
 
 #define LU_KEY_INIT_GENERIC(mod)                                        \
         static void mod##_key_init_generic(struct lu_context_key *k, ...) \
-        {                                                                        \
+        {                                                               \
                 struct lu_context_key *key = k;                         \
-                va_list args;                                                    \
-                                                                                 \
-                va_start(args, k);                                               \
-                do {                                                             \
-                        LU_CONTEXT_KEY_INIT(key);                                \
+                va_list args;                                           \
+                                                                        \
+                va_start(args, k);                                      \
+                do {                                                    \
+                        LU_CONTEXT_KEY_INIT(key);                       \
                         key = va_arg(args, struct lu_context_key *);    \
-                } while (key != NULL);                                           \
-                va_end(args);                                                    \
+                } while (key != NULL);                                  \
+                va_end(args);                                           \
         }
 
-#define LU_TYPE_INIT(mod, ...)                                         \
+#define LU_TYPE_INIT(mod, ...)                                          \
         LU_KEY_INIT_GENERIC(mod)                                        \
-        static int mod##_type_init(struct lu_device_type *t)           \
-        {                                                              \
+        static int mod##_type_init(struct lu_device_type *t)            \
+        {                                                               \
                 mod##_key_init_generic(__VA_ARGS__, NULL);              \
                 return lu_context_key_register_many(__VA_ARGS__, NULL); \
-        }                                                              \
+        }                                                               \
         struct __##mod##_dummy_type_init {;}
 
-#define LU_TYPE_FINI(mod, ...)                                         \
-        static void mod##_type_fini(struct lu_device_type *t)          \
-        {                                                              \
+#define LU_TYPE_FINI(mod, ...)                                          \
+        static void mod##_type_fini(struct lu_device_type *t)           \
+        {                                                               \
                 lu_context_key_degister_many(__VA_ARGS__, NULL);        \
-        }                                                              \
+        }                                                               \
         struct __##mod##_dummy_type_fini {;}
 
 #define LU_TYPE_START(mod, ...)                                 \
         static void mod##_type_start(struct lu_device_type *t)  \
         {                                                       \
+                lu_context_key_revive_many(__VA_ARGS__, NULL);  \
         }                                                       \
         struct __##mod##_dummy_type_start {;}
 
 #define LU_TYPE_STOP(mod, ...)                                  \
         static void mod##_type_stop(struct lu_device_type *t)   \
         {                                                       \
+                lu_context_key_quiesce_many(__VA_ARGS__, NULL); \
         }                                                       \
         struct __##mod##_dummy_type_stop {;}
 
 
 
-#define LU_TYPE_INIT_FINI(mod, ...)                                 \
-        LU_TYPE_INIT(mod, __VA_ARGS__);                             \
+#define LU_TYPE_INIT_FINI(mod, ...)             \
+        LU_TYPE_INIT(mod, __VA_ARGS__);         \
         LU_TYPE_FINI(mod, __VA_ARGS__);         \
         LU_TYPE_START(mod, __VA_ARGS__);        \
         LU_TYPE_STOP(mod, __VA_ARGS__)
@@ -1245,8 +1252,9 @@ struct lu_env {
         struct lu_context *le_ses;
 };
 
-int  lu_env_init(struct lu_env *env, struct lu_context *ses, __u32 tags);
-void lu_env_fini(struct lu_env *env);
+int  lu_env_init  (struct lu_env *env, __u32 tags);
+void lu_env_fini  (struct lu_env *env);
+int  lu_env_refill(struct lu_env *env);
 
 /** @} lu_context */
 
index ff040ba..63dab1b 100644 (file)
@@ -293,7 +293,7 @@ static inline void fid_zero(struct lu_fid *fid)
 /**
  * Check if a fid is igif or not.
  * \param fid the fid to be tested.
- * \return true if the fid is a igif; otherwise false. 
+ * \return true if the fid is a igif; otherwise false.
  */
 static inline int fid_is_igif(const struct lu_fid *fid)
 {
@@ -303,7 +303,7 @@ static inline int fid_is_igif(const struct lu_fid *fid)
 /**
  * Check if a fid is idif or not.
  * \param fid the fid to be tested.
- * \return true if the fid is a idif; otherwise false. 
+ * \return true if the fid is a idif; otherwise false.
  */
 static inline int fid_is_idif(const struct lu_fid *fid)
 {
@@ -324,7 +324,7 @@ static inline ino_t lu_igif_ino(const struct lu_fid *fid)
  * Get inode generation from a igif.
  * \param fid a igif to get inode generation from.
  * \return inode generation for the igif.
- */ 
+ */
 static inline __u32 lu_igif_gen(const struct lu_fid *fid)
 {
         return fid_oid(fid);
@@ -390,7 +390,6 @@ static inline void fid_be_to_cpu(struct lu_fid *dst, const struct lu_fid *src)
  *
  * Variable size, first byte contains the length of the whole record.
  */
-
 struct lu_fid_pack {
         char fp_len;
         char fp_area[sizeof(struct lu_fid)];
@@ -947,7 +946,7 @@ extern void lustre_swab_obd_statfs (struct obd_statfs *os);
 #define OBD_BRW_CHECK           0x10
 #define OBD_BRW_FROM_GRANT      0x20 /* the osc manages this under llite */
 #define OBD_BRW_GRANTED         0x40 /* the ost manages this */
-#define OBD_BRW_DROP            0x80 /* drop the page after IO */
+#define OBD_BRW_NOCACHE         0x80 /* this page is a part of non-cached IO */
 #define OBD_BRW_NOQUOTA        0x100
 #define OBD_BRW_SRVLOCK        0x200 /* Client holds no lock over this page */
 
@@ -976,7 +975,7 @@ extern void lustre_swab_niobuf_remote (struct niobuf_remote *nbr);
 
 /* lock value block communicated between the filter and llite */
 
-/* OST_LVB_ERR_INIT is needed because the return code in rc is 
+/* OST_LVB_ERR_INIT is needed because the return code in rc is
  * negative, i.e. because ((MASK + rc) & MASK) != MASK. */
 #define OST_LVB_ERR_INIT 0xffbadbad80000000ULL
 #define OST_LVB_ERR_MASK 0xffbadbad00000000ULL
diff --git a/lustre/include/lustre_cache.h b/lustre/include/lustre_cache.h
deleted file mode 100644 (file)
index 5bff0a2..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- 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.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright  2008 Sun Microsystems, Inc. All rights reserved
- * Use is subject to license terms.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- */
-
-#ifndef LUSTRE_CACHE_H
-#define LUSTRE_CACHE_H
-#include <obd.h>
-#include <lustre/lustre_idl.h>
-#include <lustre_dlm.h>
-
-struct lustre_cache;
-struct osc_async_page;
-struct page_removal_cb_element {
-        struct list_head        prce_list;
-        obd_page_removal_cb_t   prce_callback;
-        atomic_t                prce_refcnt;
-};
-
-typedef int (*cache_iterate_extents_cb_t)(struct lustre_cache *,
-                                          struct lustre_handle *,
-                                          struct osc_async_page *,
-                                          void *);
-typedef int (*cache_iterate_locks_cb_t)(struct lustre_cache *,
-                                        struct ldlm_res_id *,
-                                        struct lustre_handle *, void *);
-
-struct lustre_cache {
-        struct list_head         lc_locks_list;
-        spinlock_t               lc_locks_list_lock;
-        struct list_head         lc_page_removal_callback_list;
-        rwlock_t                 lc_page_removal_cb_lock; /* iterate vs modify list */
-        struct obd_device       *lc_obd;
-        obd_pin_extent_cb        lc_pin_extent_cb;
-};
-
-int cache_add_lock(struct lustre_cache *cache, struct lustre_handle *lockh);
-int cache_add_extent(struct lustre_cache *cache, struct ldlm_res_id *res,
-                     struct osc_async_page *extent,
-                     struct lustre_handle *lockh);
-void cache_remove_extent(struct lustre_cache *, struct osc_async_page *);
-int cache_add_extent_removal_cb(struct lustre_cache *cache,
-                                obd_page_removal_cb_t func_cb,
-                                obd_pin_extent_cb pin_cb);
-int cache_del_extent_removal_cb(struct lustre_cache *cache,
-                                obd_page_removal_cb_t func_cb);
-int cache_iterate_extents(struct lustre_cache *cache, struct lustre_handle *lockh,
-                          cache_iterate_extents_cb_t cb_func, void *data);
-int cache_remove_lock(struct lustre_cache *cache, struct lustre_handle *lockh);
-int cache_iterate_locks(struct lustre_cache *cache, struct ldlm_res_id *res,
-                        cache_iterate_locks_cb_t cb_fun, void *data);
-struct lustre_cache *cache_create(struct obd_device *obd);
-int cache_destroy(struct lustre_cache *cache);
-
-
-#endif /* LUSTRE_CACHE_H */
index 1bd1c53..aa0e358 100644 (file)
@@ -261,13 +261,13 @@ struct ldlm_pool_ops {
         int (*po_setup)(struct ldlm_pool *pl, int limit);
 };
 
-/** 
- * One second for pools thread check interval. Each pool has own period. 
+/**
+ * One second for pools thread check interval. Each pool has own period.
  */
 #define LDLM_POOLS_THREAD_PERIOD (1)
 
-/** 
- * 5% margin for modest pools. See ldlm_pool.c for details. 
+/**
+ * 5% margin for modest pools. See ldlm_pool.c for details.
  */
 #define LDLM_POOLS_MODEST_MARGIN (5)
 
@@ -432,7 +432,6 @@ struct ldlm_namespace {
 
         unsigned int           ns_max_unused;
         unsigned int           ns_max_age;
-
          /**
           * Seconds.
           */
@@ -546,7 +545,7 @@ struct ldlm_interval_tree {
 };
 
 struct ldlm_lock {
-        /** 
+        /**
          * Must be first in the structure.
          */
         struct portals_handle    l_handle;
@@ -554,34 +553,34 @@ struct ldlm_lock {
          * Lock reference count.
          */
         atomic_t                 l_refc;
-        /** 
+        /**
          * Internal spinlock protects l_resource.  we should hold this lock
          * first before grabbing res_lock.
          */
         spinlock_t               l_lock;
-        /** 
-         * ldlm_lock_change_resource() can change this. 
+        /**
+         * ldlm_lock_change_resource() can change this.
          */
         struct ldlm_resource    *l_resource;
-        /** 
+        /**
          * Protected by ns_hash_lock. List item for client side lru list.
          */
         struct list_head         l_lru;
-        /** 
-         * Protected by lr_lock, linkage to resource's lock queues. 
+        /**
+         * Protected by lr_lock, linkage to resource's lock queues.
          */
         struct list_head         l_res_link;
-        /** 
-         * Tree node for ldlm_extent. 
+        /**
+         * Tree node for ldlm_extent.
          */
         struct ldlm_interval    *l_tree_node;
-        /** 
+        /**
          * Protected by per-bucket exp->exp_lock_hash locks. Per export hash
          * of locks.
          */
         struct hlist_node        l_exp_hash;
-        /** 
-         * Protected by lr_lock. Requested mode. 
+        /**
+         * Protected by lr_lock. Requested mode.
          */
         ldlm_mode_t              l_req_mode;
         /**
@@ -633,27 +632,27 @@ struct ldlm_lock {
          */
         __u8                  l_destroyed;
 
-        /** 
+        /**
          * If the lock is granted, a process sleeps on this waitq to learn when
          * it's no longer in use.  If the lock is not granted, a process sleeps
-         * on this waitq to learn when it becomes granted. 
+         * on this waitq to learn when it becomes granted.
          */
         cfs_waitq_t           l_waitq;
 
         struct timeval        l_enqueued_time;
 
         /**
-         * Jiffies. Should be converted to time if needed. 
+         * Jiffies. Should be converted to time if needed.
          */
         cfs_time_t            l_last_used;
 
         struct ldlm_extent    l_req_extent;
 
-        /* 
-         * Client-side-only members. 
+        /*
+         * Client-side-only members.
          */
-         
-        /** 
+
+        /**
          * Temporary storage for an LVB received during an enqueue operation.
          */
         __u32                 l_lvb_len;
@@ -666,43 +665,43 @@ struct ldlm_lock {
 
         struct list_head      l_cache_locks_list;
 
-        /* 
-         * Server-side-only members. 
+        /*
+         * Server-side-only members.
          */
 
-        /* connection cookie for the client originated the opeation */
+        /** connection cookie for the client originated the operation. */
         __u64                 l_client_cookie;
 
-        /** 
+        /**
          * Protected by elt_lock. Callbacks pending.
          */
         struct list_head      l_pending_chain;
 
         cfs_time_t            l_callback_timeout;
 
-        /** 
-         * Pid which created this lock. 
+        /**
+         * Pid which created this lock.
          */
         __u32                 l_pid;
 
-        /** 
-         * For ldlm_add_ast_work_item(). 
+        /**
+         * For ldlm_add_ast_work_item().
          */
         struct list_head      l_bl_ast;
-        /** 
-         * For ldlm_add_ast_work_item(). 
+        /**
+         * For ldlm_add_ast_work_item().
          */
         struct list_head      l_cp_ast;
-        /** 
-         * For ldlm_add_ast_work_item(). 
+        /**
+         * For ldlm_add_ast_work_item().
          */
         struct list_head      l_rk_ast;
 
         struct ldlm_lock     *l_blocking_lock;
         int                   l_bl_ast_run;
 
-        /** 
-         * Protected by lr_lock, linkages to "skip lists". 
+        /**
+         * Protected by lr_lock, linkages to "skip lists".
          */
         struct list_head      l_sl_mode;
         struct list_head      l_sl_policy;
@@ -871,7 +870,6 @@ void ldlm_lock2handle(const struct ldlm_lock *lock,
                       struct lustre_handle *lockh);
 struct ldlm_lock *__ldlm_handle2lock(const struct lustre_handle *, int flags);
 void ldlm_cancel_callback(struct ldlm_lock *);
-int ldlm_lock_set_data(struct lustre_handle *, void *data);
 int ldlm_lock_remove_from_lru(struct ldlm_lock *);
 
 static inline struct ldlm_lock *ldlm_handle2lock(const struct lustre_handle *h)
@@ -959,12 +957,10 @@ int  ldlm_lock_addref_try(struct lustre_handle *lockh, __u32 mode);
 void ldlm_lock_decref(struct lustre_handle *lockh, __u32 mode);
 void ldlm_lock_decref_and_cancel(struct lustre_handle *lockh, __u32 mode);
 void ldlm_lock_allow_match(struct ldlm_lock *lock);
-int ldlm_lock_fast_match(struct ldlm_lock *, int, obd_off, obd_off, void **);
-void ldlm_lock_fast_release(void *, int);
 ldlm_mode_t ldlm_lock_match(struct ldlm_namespace *ns, int flags,
                             const struct ldlm_res_id *, ldlm_type_t type,
                             ldlm_policy_data_t *, ldlm_mode_t mode,
-                            struct lustre_handle *);
+                            struct lustre_handle *, int unref);
 struct ldlm_resource *ldlm_lock_convert(struct ldlm_lock *lock, int new_mode,
                                         __u32 *flags);
 void ldlm_lock_downgrade(struct ldlm_lock *lock, int new_mode);
@@ -1016,7 +1012,7 @@ int ldlm_lock_change_resource(struct ldlm_namespace *, struct ldlm_lock *,
                               const struct ldlm_res_id *);
 
 #define LDLM_RESOURCE_ADDREF(res) do {                                  \
-        lu_ref_add(&(res)->lr_reference, __FUNCTION__, cfs_current());  \
+        lu_ref_add_atomic(&(res)->lr_reference, __FUNCTION__, cfs_current());  \
 } while (0)
 
 #define LDLM_RESOURCE_DELREF(res) do {                                  \
index 439d0dd..34bb9f1 100644 (file)
@@ -165,15 +165,15 @@ static inline int ll_ocd_update(struct obd_device *host,
         RETURN(result);
 }
 
-/*      
+/*
  * Chain of hash overflow pages.
- */            
+ */
 struct ll_dir_chain {
         /* XXX something. Later */
 };
-        
+
 static inline void ll_dir_chain_init(struct ll_dir_chain *chain)
-{       
+{
 }
 
 static inline void ll_dir_chain_fini(struct ll_dir_chain *chain)
index 34b5831..558930d 100644 (file)
@@ -213,7 +213,7 @@ union ptlrpc_async_args {
          * a pointer to it here.  The pointer_arg ensures this struct is at
          * least big enough for that. */
         void      *pointer_arg[9];
-        __u64      space[4];
+        __u64      space[5];
 };
 
 struct ptlrpc_request_set;
@@ -803,7 +803,11 @@ enum ptlrpcd_ctl_flags {
          * Ptlrpc thread stop force flag. This will cause also
          * aborting any inflight rpcs handled by thread.
          */
-        LIOD_STOP_FORCE  = 1 << 2
+        LIOD_STOP_FORCE  = 1 << 2,
+        /**
+         * This is a recovery ptlrpc thread.
+         */
+        LIOD_RECOVERY    = 1 << 3
 };
 
 /* ptlrpc/events.c */
@@ -1214,10 +1218,25 @@ void ping_evictor_stop(void);
 int ptlrpc_check_and_wait_suspend(struct ptlrpc_request *req);
 
 /* ptlrpc/ptlrpcd.c */
-int ptlrpcd_start(char *name, struct ptlrpcd_ctl *pc);
+
+/**
+ * Ptlrpcd scope is a set of two threads: ptlrpcd-foo and ptlrpcd-foo-rcv,
+ * these threads are used to asynchronously send requests queued with
+ * ptlrpcd_add_req(req, PCSOPE_FOO), and to handle completion call-backs for
+ * such requests. Multiple scopes are needed to avoid dead-locks.
+ */
+enum ptlrpcd_scope {
+        /** Scope of bulk read-write rpcs. */
+        PSCOPE_BRW,
+        /** Everything else. */
+        PSCOPE_OTHER,
+        PSCOPE_NR
+};
+
+int ptlrpcd_start(const char *name, struct ptlrpcd_ctl *pc);
 void ptlrpcd_stop(struct ptlrpcd_ctl *pc, int force);
 void ptlrpcd_wake(struct ptlrpc_request *req);
-void ptlrpcd_add_req(struct ptlrpc_request *req);
+void ptlrpcd_add_req(struct ptlrpc_request *req, enum ptlrpcd_scope scope);
 int ptlrpcd_addref(void);
 void ptlrpcd_decref(void);
 
index 556728d..c2fc95c 100644 (file)
@@ -88,7 +88,9 @@ struct md_ucred {
        struct md_identity *mu_identity;
 };
 
-#define MD_CAPAINFO_MAX 5
+enum {
+        MD_CAPAINFO_MAX = 5
+};
 
 /** there are at most 5 fids in one operation, see rename, NOTE the last one
  * is a temporary one used for is_subdir() */
@@ -335,9 +337,9 @@ struct md_upcall {
 };
 
 struct md_device {
-        struct lu_device             md_lu_dev;
+        struct lu_device                   md_lu_dev;
         const struct md_device_operations *md_ops;
-        struct md_upcall             md_upcall;
+        struct md_upcall                   md_upcall;
 };
 
 static inline void md_upcall_init(struct md_device *m, void *upcl)
@@ -377,7 +379,7 @@ static inline int md_do_upcall(const struct lu_env *env, struct md_device *m,
 }
 
 struct md_object {
-        struct lu_object             mo_lu;
+        struct lu_object                   mo_lu;
         const struct md_object_operations *mo_ops;
         const struct md_dir_operations    *mo_dir_ops;
 };
@@ -454,12 +456,12 @@ static inline struct md_site *lu_site2md(const struct lu_site *s)
 
 static inline int md_device_init(struct md_device *md, struct lu_device_type *t)
 {
-       return lu_device_init(&md->md_lu_dev, t);
+        return lu_device_init(&md->md_lu_dev, t);
 }
 
 static inline void md_device_fini(struct md_device *md)
 {
-       lu_device_fini(&md->md_lu_dev);
+        lu_device_fini(&md->md_lu_dev);
 }
 
 static inline struct md_object *md_object_find_slice(const struct lu_env *env,
index b42e2c3..15d4273 100644 (file)
@@ -175,7 +175,7 @@ struct lov_stripe_md {
 
 struct obd_info;
 
-typedef int (*obd_enqueue_update_f)(struct obd_info *oinfo, int rc);
+typedef int (*obd_enqueue_update_f)(void *cookie, int rc);
 
 /* obd info for a particular level (lov, osc). */
 struct obd_info {
@@ -239,52 +239,6 @@ struct brw_page {
         obd_flag flag;
 };
 
-enum async_flags {
-        ASYNC_READY = 0x1, /* ap_make_ready will not be called before this
-                              page is added to an rpc */
-        ASYNC_URGENT = 0x2, /* page must be put into an RPC before return */
-        ASYNC_COUNT_STABLE = 0x4, /* ap_refresh_count will not be called
-                                     to give the caller a chance to update
-                                     or cancel the size of the io */
-        ASYNC_GROUP_SYNC = 0x8,  /* ap_completion will not be called, instead
-                                    the page is accounted for in the
-                                    obd_io_group given to
-                                    obd_queue_group_io */
-};
-
-struct obd_async_page_ops {
-        int  (*ap_make_ready)(void *data, int cmd);
-        int  (*ap_refresh_count)(void *data, int cmd);
-        void (*ap_fill_obdo)(void *data, int cmd, struct obdo *oa);
-        void (*ap_update_obdo)(void *data, int cmd, struct obdo *oa,
-                               obd_valid valid);
-        int  (*ap_completion)(void *data, int cmd, struct obdo *oa, int rc);
-        struct obd_capa *(*ap_lookup_capa)(void *data, int cmd);
-};
-
-/* the `oig' is passed down from a caller of obd rw methods.  the callee
- * records enough state such that the caller can sleep on the oig and
- * be woken when all the callees have finished their work */
-struct obd_io_group {
-        spinlock_t      oig_lock;
-        atomic_t        oig_refcount;
-        int             oig_pending;
-        int             oig_rc;
-        struct list_head oig_occ_list;
-        cfs_waitq_t     oig_waitq;
-};
-
-/* the oig callback context lets the callee of obd rw methods register
- * for callbacks from the caller. */
-struct oig_callback_context {
-        struct list_head occ_oig_item;
-        /* called when the caller has received a signal while sleeping.
-         * callees of this method are encouraged to abort their state
-         * in the oig.  This may be called multiple times. */
-        void (*occ_interrupted)(struct oig_callback_context *occ);
-        unsigned long interrupted:1;
-};
-
 /* Individual type definitions */
 
 struct ost_server_data;
@@ -296,11 +250,6 @@ struct obd_device_target {
         struct lustre_quota_ctxt  obt_qctxt;
 };
 
-typedef void (*obd_pin_extent_cb)(void *data);
-typedef int (*obd_page_removal_cb_t)(void *data, int discard);
-typedef int (*obd_lock_cancel_cb)(struct ldlm_lock *,struct ldlm_lock_desc *,
-                                   void *, int);
-
 /* llog contexts */
 enum llog_ctxt_id {
         LLOG_CONFIG_ORIG_CTXT  =  0,
@@ -426,7 +375,6 @@ struct filter_obd {
 
 struct mdc_rpc_lock;
 struct obd_import;
-struct lustre_cache;
 struct client_obd {
         struct rw_semaphore      cl_sem;
         struct obd_uuid          cl_target_uuid;
@@ -448,6 +396,7 @@ struct client_obd {
         /* the grant values are protected by loi_list_lock below */
         long                     cl_dirty;         /* all _dirty_ in bytes */
         long                     cl_dirty_max;     /* allowed w/o rpc */
+        long                     cl_dirty_transit; /* dirty synchronous */
         long                     cl_avail_grant;   /* bytes of credit for ost */
         long                     cl_lost_grant;    /* lost credits (trunc) */
         struct list_head         cl_cache_waiters; /* waiting for cache/grant */
@@ -521,10 +470,6 @@ struct client_obd {
         struct lu_client_seq    *cl_seq;
 
         atomic_t                 cl_resends; /* resend count */
-
-        /* Cache of triples */
-        struct lustre_cache     *cl_cache;
-        obd_lock_cancel_cb       cl_ext_lock_cancel_cb;
 };
 #define obd2cli_tgt(obd) ((char *)(obd)->u.cli.cl_target_uuid.uuid)
 
@@ -639,6 +584,7 @@ struct echo_client_obd {
         struct obd_export   *ec_exp;   /* the local connection to osc/lov */
         spinlock_t           ec_lock;
         struct list_head     ec_objects;
+        struct list_head     ec_locks;
         int                  ec_nstripes;
         __u64                ec_unique;
 };
@@ -734,9 +680,6 @@ struct lov_obd {
         __u32                   lov_death_row;/* tgts scheduled to be deleted */
         __u32                   lov_tgt_size;   /* size of tgts array */
         int                     lov_connects;
-        obd_page_removal_cb_t   lov_page_removal_cb;
-        obd_pin_extent_cb       lov_page_pin_cb;
-        obd_lock_cancel_cb      lov_lock_cancel_cb;
         int                     lov_pool_count;
         lustre_hash_t          *lov_pools_hash_body; /* used for key access */
         struct list_head        lov_pool_list; /* used for sequential access */
@@ -801,8 +744,10 @@ struct niobuf_local {
 #define LUSTRE_CMM_NAME         "cmm"
 #define LUSTRE_MDD_NAME         "mdd"
 #define LUSTRE_OSD_NAME         "osd"
+#define LUSTRE_VVP_NAME         "vvp"
 #define LUSTRE_LMV_NAME         "lmv"
 #define LUSTRE_CMM_MDC_NAME     "cmm-mdc"
+#define LUSTRE_SLP_NAME         "slp"
 
 /* obd device type names */
  /* FIXME all the references to LUSTRE_MDS_NAME should be swapped with LUSTRE_MDT_NAME */
@@ -1281,47 +1226,6 @@ struct obd_ops {
         int (*o_brw)(int rw, struct obd_export *exp, struct obd_info *oinfo,
                      obd_count oa_bufs, struct brw_page *pgarr,
                      struct obd_trans_info *oti);
-        int (*o_brw_async)(int rw, struct obd_export *exp,
-                           struct obd_info *oinfo, obd_count oa_bufs,
-                           struct brw_page *pgarr, struct obd_trans_info *oti,
-                           struct ptlrpc_request_set *);
-        int (*o_prep_async_page)(struct obd_export *exp,
-                                 struct lov_stripe_md *lsm,
-                                 struct lov_oinfo *loi,
-                                 cfs_page_t *page, obd_off offset,
-                                 struct obd_async_page_ops *ops, void *data,
-                                 void **res, int nocache,
-                                 struct lustre_handle *lockh);
-        int (*o_reget_short_lock)(struct obd_export *exp,
-                                  struct lov_stripe_md *lsm,
-                                  void **res, int rw,
-                                  obd_off start, obd_off end,
-                                  void **cookie);
-        int (*o_release_short_lock)(struct obd_export *exp,
-                                    struct lov_stripe_md *lsm, obd_off end,
-                                    void *cookie, int rw);
-        int (*o_queue_async_io)(struct obd_export *exp,
-                                struct lov_stripe_md *lsm,
-                                struct lov_oinfo *loi, void *cookie,
-                                int cmd, obd_off off, int count,
-                                obd_flag brw_flags, obd_flag async_flags);
-        int (*o_queue_group_io)(struct obd_export *exp,
-                                struct lov_stripe_md *lsm,
-                                struct lov_oinfo *loi,
-                                struct obd_io_group *oig,
-                                void *cookie, int cmd, obd_off off, int count,
-                                obd_flag brw_flags, obd_flag async_flags);
-        int (*o_trigger_group_io)(struct obd_export *exp,
-                                  struct lov_stripe_md *lsm,
-                                  struct lov_oinfo *loi,
-                                  struct obd_io_group *oig);
-        int (*o_set_async_flags)(struct obd_export *exp,
-                                struct lov_stripe_md *lsm,
-                                struct lov_oinfo *loi, void *cookie,
-                                obd_flag async_flags);
-        int (*o_teardown_async_page)(struct obd_export *exp,
-                                     struct lov_stripe_md *lsm,
-                                     struct lov_oinfo *loi, void *cookie);
         int (*o_merge_lvb)(struct obd_export *exp, struct lov_stripe_md *lsm,
                            struct ost_lvb *lvb, int kms_only);
         int (*o_adjust_kms)(struct obd_export *exp, struct lov_stripe_md *lsm,
@@ -1355,9 +1259,6 @@ struct obd_ops {
         int (*o_enqueue)(struct obd_export *, struct obd_info *oinfo,
                          struct ldlm_enqueue_info *einfo,
                          struct ptlrpc_request_set *rqset);
-        int (*o_match)(struct obd_export *, struct lov_stripe_md *, __u32 type,
-                       ldlm_policy_data_t *, __u32 mode, int *flags, void *data,
-                       struct lustre_handle *lockh);
         int (*o_change_cbdata)(struct obd_export *, struct lov_stripe_md *,
                                ldlm_iterator_t it, void *data);
         int (*o_cancel)(struct obd_export *, struct lov_stripe_md *md,
@@ -1396,15 +1297,6 @@ struct obd_ops {
 
         int (*o_ping)(struct obd_export *exp);
 
-        int (*o_register_page_removal_cb)(struct obd_export *exp,
-                                          obd_page_removal_cb_t cb,
-                                          obd_pin_extent_cb pin_cb);
-        int (*o_unregister_page_removal_cb)(struct obd_export *exp,
-                                            obd_page_removal_cb_t cb);
-        int (*o_register_lock_cancel_cb)(struct obd_export *exp,
-                                       obd_lock_cancel_cb cb);
-        int (*o_unregister_lock_cancel_cb)(struct obd_export *exp,
-                                         obd_lock_cancel_cb cb);
         /* pools methods */
         int (*o_pool_new)(struct obd_device *obd, char *poolname);
         int (*o_pool_del)(struct obd_device *obd, char *poolname);
index 045e3ff..3e885b2 100644 (file)
@@ -92,13 +92,6 @@ struct obd_device * class_devices_in_group(struct obd_uuid *grp_uuid,
                                            int *next);
 struct obd_device * class_num2obd(int num);
 
-int oig_init(struct obd_io_group **oig);
-int oig_add_one(struct obd_io_group *oig, struct oig_callback_context *occ);
-void oig_complete_one(struct obd_io_group *oig,
-                      struct oig_callback_context *occ, int rc);
-void oig_release(struct obd_io_group *oig);
-int oig_wait(struct obd_io_group *oig);
-
 char *obd_export_nid2str(struct obd_export *exp);
 
 int obd_export_evict_by_nid(struct obd_device *obd, const char *nid);
@@ -107,6 +100,7 @@ int obd_export_evict_by_uuid(struct obd_device *obd, const char *uuid);
 int obd_zombie_impexp_init(void);
 void obd_zombie_impexp_stop(void);
 void obd_zombie_impexp_cull(void);
+void obd_zombie_barrier(void);
 
 /* obd_config.c */
 int class_process_config(struct lustre_cfg *lcfg);
@@ -411,26 +405,39 @@ static inline int obd_set_info_async(struct obd_export *exp, obd_count keylen,
         RETURN(rc);
 }
 
-#ifdef __KERNEL__
+/*
+ * obd-lu integration.
+ *
+ * Functionality is being moved into new lu_device-based layering, but some
+ * pieces of configuration process are still based on obd devices.
+ *
+ * Specifically, lu_device_type_operations::ldto_device_alloc() methods fully
+ * subsume ->o_setup() methods of obd devices they replace. The same for
+ * lu_device_operations::ldo_process_config() and ->o_process_config(). As a
+ * result, obd_setup() and obd_process_config() branch and call one XOR
+ * another.
+ *
+ * Yet neither lu_device_type_operations::ldto_device_fini() nor
+ * lu_device_type_operations::ldto_device_free() fully implement the
+ * functionality of ->o_precleanup() and ->o_cleanup() they override. Hence,
+ * obd_precleanup() and obd_cleanup() call both lu_device and obd operations.
+ */
+
 #define DECLARE_LU_VARS(ldt, d)                 \
-        struct lu_device_type *ldt;             \
+        struct lu_device_type *ldt;       \
         struct lu_device *d
-#else
-#define DECLARE_LU_VARS(ldt, d)                                 \
-        extern void __placeholder_to_put_a_semicolon(void)
-#endif
+
 static inline int obd_setup(struct obd_device *obd, struct lustre_cfg *cfg)
 {
         int rc;
         DECLARE_LU_VARS(ldt, d);
         ENTRY;
 
-#ifdef __KERNEL__
         ldt = obd->obd_type->typ_lu;
         if (ldt != NULL) {
                 struct lu_env env;
 
-                rc = lu_env_init(&env, NULL, ldt->ldt_ctx_tags);
+                rc = lu_env_init(&env, ldt->ldt_ctx_tags);
                 if (rc == 0) {
                         d = ldt->ldt_ops->ldto_device_alloc(&env, ldt, cfg);
                         lu_env_fini(&env);
@@ -441,9 +448,7 @@ static inline int obd_setup(struct obd_device *obd, struct lustre_cfg *cfg)
                         } else
                                 rc = PTR_ERR(d);
                 }
-        } else
-#endif
-        {
+        } else {
                 OBD_CHECK_DT_OP(obd, setup, -EOPNOTSUPP);
                 OBD_COUNTER_INCREMENT(obd, setup);
                 rc = OBP(obd, setup)(obd, cfg);
@@ -459,29 +464,23 @@ static inline int obd_precleanup(struct obd_device *obd,
         ENTRY;
 
         OBD_CHECK_DEV(obd);
-#ifdef __KERNEL__
         ldt = obd->obd_type->typ_lu;
         d = obd->obd_lu_dev;
         if (ldt != NULL && d != NULL) {
                 if (cleanup_stage == OBD_CLEANUP_EXPORTS) {
                         struct lu_env env;
 
-                        rc = lu_env_init(&env, NULL, ldt->ldt_ctx_tags);
+                        rc = lu_env_init(&env, ldt->ldt_ctx_tags);
                         if (rc == 0) {
                                 ldt->ldt_ops->ldto_device_fini(&env, d);
                                 lu_env_fini(&env);
                         }
-                } else {
-                        rc = 0;
                 }
-        } else
-#endif
-        {
-                OBD_CHECK_DT_OP(obd, precleanup, 0);
-                rc = OBP(obd, precleanup)(obd, cleanup_stage);
         }
-
+        OBD_CHECK_DT_OP(obd, precleanup, 0);
         OBD_COUNTER_INCREMENT(obd, precleanup);
+
+        rc = OBP(obd, precleanup)(obd, cleanup_stage);
         RETURN(rc);
 }
 
@@ -493,25 +492,22 @@ static inline int obd_cleanup(struct obd_device *obd)
 
         OBD_CHECK_DEV(obd);
 
-#ifdef __KERNEL__
         ldt = obd->obd_type->typ_lu;
         d = obd->obd_lu_dev;
         if (ldt != NULL && d != NULL) {
                 struct lu_env env;
 
-                rc = lu_env_init(&env, NULL, ldt->ldt_ctx_tags);
+                rc = lu_env_init(&env, ldt->ldt_ctx_tags);
                 if (rc == 0) {
                         ldt->ldt_ops->ldto_device_free(&env, d);
                         lu_env_fini(&env);
                         obd->obd_lu_dev = NULL;
                 }
-        } else
-#endif
-        {
-                OBD_CHECK_DT_OP(obd, cleanup, 0);
-                rc = OBP(obd, cleanup)(obd);
         }
+        OBD_CHECK_DT_OP(obd, cleanup, 0);
         OBD_COUNTER_INCREMENT(obd, cleanup);
+
+        rc = OBP(obd, cleanup)(obd);
         RETURN(rc);
 }
 
@@ -524,20 +520,17 @@ obd_process_config(struct obd_device *obd, int datalen, void *data)
 
         OBD_CHECK_DEV(obd);
 
-#ifdef __KERNEL__
         ldt = obd->obd_type->typ_lu;
         d = obd->obd_lu_dev;
         if (ldt != NULL && d != NULL) {
                 struct lu_env env;
 
-                rc = lu_env_init(&env, NULL, ldt->ldt_ctx_tags);
+                rc = lu_env_init(&env, ldt->ldt_ctx_tags);
                 if (rc == 0) {
                         rc = d->ld_ops->ldo_process_config(&env, d, data);
                         lu_env_fini(&env);
                 }
-        } else
-#endif
-        {
+        } else {
                 OBD_CHECK_DT_OP(obd, process_config, -EOPNOTSUPP);
                 rc = OBP(obd, process_config)(obd, datalen, data);
         }
@@ -624,9 +617,13 @@ static inline int obd_alloc_memmd(struct obd_export *exp,
 static inline int obd_free_memmd(struct obd_export *exp,
                                  struct lov_stripe_md **mem_tgt)
 {
+        int rc;
+
         LASSERT(mem_tgt);
         LASSERT(*mem_tgt);
-        return obd_unpackmd(exp, mem_tgt, NULL, 0);
+        rc = obd_unpackmd(exp, mem_tgt, NULL, 0);
+        *mem_tgt = NULL;
+        return rc;
 }
 
 static inline int obd_checkmd(struct obd_export *exp,
@@ -811,10 +808,8 @@ static inline int obd_connect(const struct lu_env *env,
                               void *localdata)
 {
         int rc;
-#ifdef LIBCFS_DEBUG
         __u64 ocf = d ? d->ocd_connect_flags : 0; /* for post-condition
                                                    * check */
-#endif
         ENTRY;
 
         OBD_CHECK_DEV_ACTIVE(obd);
@@ -836,10 +831,8 @@ static inline int obd_reconnect(const struct lu_env *env,
                                 void *localdata)
 {
         int rc;
-#ifdef LIBCFS_DEBUG
         __u64 ocf = d ? d->ocd_connect_flags : 0; /* for post-condition
                                                    * check */
-#endif
 
         ENTRY;
 
@@ -1200,230 +1193,6 @@ static inline int obd_brw(int cmd, struct obd_export *exp,
         RETURN(rc);
 }
 
-static inline int obd_brw_async(int cmd, struct obd_export *exp,
-                                struct obd_info *oinfo, obd_count oa_bufs,
-                                struct brw_page *pg, struct obd_trans_info *oti,
-                                struct ptlrpc_request_set *set)
-{
-        int rc;
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, brw_async);
-        EXP_COUNTER_INCREMENT(exp, brw_async);
-
-        if (!(cmd & OBD_BRW_RWMASK)) {
-                CERROR("obd_brw: cmd must be OBD_BRW_READ or OBD_BRW_WRITE\n");
-                LBUG();
-        }
-
-        rc = OBP(exp->exp_obd, brw_async)(cmd, exp, oinfo, oa_bufs, pg,oti,set);
-        RETURN(rc);
-}
-
-static inline int obd_brw_rqset(int cmd, struct obd_export *exp,
-                                struct obdo *oa, struct lov_stripe_md *lsm,
-                                obd_count oa_bufs, struct brw_page *pg,
-                                struct obd_trans_info *oti,
-                                struct obd_capa *ocapa)
-{
-        struct ptlrpc_request_set *set = NULL;
-        struct obd_info oinfo = { { { 0 } } };
-        int rc = 0;
-        ENTRY;
-
-        set =  ptlrpc_prep_set();
-        if (set == NULL)
-                RETURN(-ENOMEM);
-
-        oinfo.oi_oa = oa;
-        oinfo.oi_md = lsm;
-        oinfo.oi_capa = ocapa;
-        rc = obd_brw_async(cmd, exp, &oinfo, oa_bufs, pg, oti, set);
-        if (rc == 0) {
-                rc = ptlrpc_set_wait(set);
-                if (rc)
-                        CERROR("error from callback: rc = %d\n", rc);
-        } else {
-                CDEBUG(rc == -ENOSPC ? D_INODE : D_ERROR,
-                       "error from obd_brw_async: rc = %d\n", rc);
-        }
-        ptlrpc_set_destroy(set);
-        RETURN(rc);
-}
-
-static inline  int obd_prep_async_page(struct obd_export *exp,
-                                       struct lov_stripe_md *lsm,
-                                       struct lov_oinfo *loi,
-                                       cfs_page_t *page, obd_off offset,
-                                       struct obd_async_page_ops *ops,
-                                       void *data, void **res, int nocache,
-                                       struct lustre_handle *lockh)
-{
-        int ret;
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, prep_async_page);
-        EXP_COUNTER_INCREMENT(exp, prep_async_page);
-
-        ret = OBP(exp->exp_obd, prep_async_page)(exp, lsm, loi, page, offset,
-                                                 ops, data, res, nocache,
-                                                 lockh);
-        RETURN(ret);
-}
-
-/**
- * Checks if requested extent lock is compatible with a lock under the page.
- *
- * Checks if the lock under \a page is compatible with a read or write lock
- * (specified by \a rw) for an extent [\a start , \a end].
- *
- * \param exp obd export (lov or osc)
- * \param lsm striping information for the file
- * \param res async_page placeholder
- * \param rw OBD_BRW_READ if requested for reading,
- *           OBD_BRW_WRITE if requested for writing
- * \param start start of the requested extent
- * \param end end of the requested extent
- * \param cookie transparent parameter for passing locking context
- *
- * \post result == 1, *cookie == context, appropriate lock is referenced or
- *
- * \retval 1 owned lock is reused for the request
- * \retval 0 no lock reused for the request
- * \retval -ENOTSUPP reget_short_lock is not exported at this layer
- *
- * \see obd_release_short_lock
- */
-static inline int obd_reget_short_lock(struct obd_export *exp,
-                                       struct lov_stripe_md *lsm,
-                                       void **res, int rw,
-                                       obd_off start, obd_off end,
-                                       void **cookie)
-{
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, reget_short_lock);
-        EXP_COUNTER_INCREMENT(exp, reget_short_lock);
-
-        RETURN(OBP(exp->exp_obd, reget_short_lock)(exp, lsm, res, rw,
-                                                   start, end, cookie));
-}
-
-
-/**
- * Releases a reference to a lock taken in a "fast" way.
- *
- * Releases a read or write (specified by \a rw) lock
- * referenced by \a cookie.
- *
- * \param exp obd export (lov or osc)
- * \param lsm striping information for the file
- * \param end end of the locked extent
- * \param rw OBD_BRW_READ if requested for reading,
- *           OBD_BRW_WRITE if requested for writing
- * \param cookie transparent parameter for passing locking context
- *
- * \post appropriate lock is dereferenced
- *
- * \see obd_reget_short_lock
- */
-static inline int obd_release_short_lock(struct obd_export *exp,
-                                         struct lov_stripe_md *lsm, obd_off end,
-                                         void *cookie, int rw)
-{
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, release_short_lock);
-        EXP_COUNTER_INCREMENT(exp, release_short_lock);
-
-        RETURN(OBP(exp->exp_obd, release_short_lock)(exp, lsm, end,
-                                                     cookie, rw));
-}
-
-static inline int obd_queue_async_io(struct obd_export *exp,
-                                     struct lov_stripe_md *lsm,
-                                     struct lov_oinfo *loi, void *cookie,
-                                     int cmd, obd_off off, int count,
-                                     obd_flag brw_flags, obd_flag async_flags)
-{
-        int rc;
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, queue_async_io);
-        EXP_COUNTER_INCREMENT(exp, queue_async_io);
-        LASSERT(cmd & OBD_BRW_RWMASK);
-
-        rc = OBP(exp->exp_obd, queue_async_io)(exp, lsm, loi, cookie, cmd, off,
-                                               count, brw_flags, async_flags);
-        RETURN(rc);
-}
-
-static inline int obd_set_async_flags(struct obd_export *exp,
-                                      struct lov_stripe_md *lsm,
-                                      struct lov_oinfo *loi, void *cookie,
-                                      obd_flag async_flags)
-{
-        int rc;
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, set_async_flags);
-        EXP_COUNTER_INCREMENT(exp, set_async_flags);
-
-        rc = OBP(exp->exp_obd, set_async_flags)(exp, lsm, loi, cookie,
-                                                async_flags);
-        RETURN(rc);
-}
-
-static inline int obd_queue_group_io(struct obd_export *exp,
-                                     struct lov_stripe_md *lsm,
-                                     struct lov_oinfo *loi,
-                                     struct obd_io_group *oig,
-                                     void *cookie, int cmd, obd_off off,
-                                     int count, obd_flag brw_flags,
-                                     obd_flag async_flags)
-{
-        int rc;
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, queue_group_io);
-        EXP_COUNTER_INCREMENT(exp, queue_group_io);
-        LASSERT(cmd & OBD_BRW_RWMASK);
-
-        rc = OBP(exp->exp_obd, queue_group_io)(exp, lsm, loi, oig, cookie,
-                                               cmd, off, count, brw_flags,
-                                               async_flags);
-        RETURN(rc);
-}
-
-static inline int obd_trigger_group_io(struct obd_export *exp,
-                                       struct lov_stripe_md *lsm,
-                                       struct lov_oinfo *loi,
-                                       struct obd_io_group *oig)
-{
-        int rc;
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, trigger_group_io);
-        EXP_COUNTER_INCREMENT(exp, trigger_group_io);
-
-        rc = OBP(exp->exp_obd, trigger_group_io)(exp, lsm, loi, oig);
-        RETURN(rc);
-}
-
-static inline int obd_teardown_async_page(struct obd_export *exp,
-                                          struct lov_stripe_md *lsm,
-                                          struct lov_oinfo *loi, void *cookie)
-{
-        int rc;
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, teardown_async_page);
-        EXP_COUNTER_INCREMENT(exp, teardown_async_page);
-
-        rc = OBP(exp->exp_obd, teardown_async_page)(exp, lsm, loi, cookie);
-        RETURN(rc);
-}
-
 static inline int obd_preprw(int cmd, struct obd_export *exp, struct obdo *oa,
                              int objcount, struct obd_ioobj *obj,
                              struct niobuf_remote *remote, int *pages,
@@ -1536,21 +1305,6 @@ static inline int obd_enqueue(struct obd_export *exp,
         RETURN(rc);
 }
 
-static inline int obd_match(struct obd_export *exp, struct lov_stripe_md *ea,
-                            __u32 type, ldlm_policy_data_t *policy, __u32 mode,
-                            int *flags, void *data, struct lustre_handle *lockh)
-{
-        int rc;
-        ENTRY;
-
-        EXP_CHECK_DT_OP(exp, match);
-        EXP_COUNTER_INCREMENT(exp, match);
-
-        rc = OBP(exp->exp_obd, match)(exp, ea, type, policy, mode, flags, data,
-                                      lockh);
-        RETURN(rc);
-}
-
 static inline int obd_change_cbdata(struct obd_export *exp,
                                     struct lov_stripe_md *lsm,
                                     ldlm_iterator_t it, void *data)
@@ -1769,6 +1523,7 @@ static inline int obd_register_observer(struct obd_device *obd,
         RETURN(0);
 }
 
+#if 0
 static inline int obd_register_page_removal_cb(struct obd_export *exp,
                                                obd_page_removal_cb_t cb,
                                                obd_pin_extent_cb pin_cb)
@@ -1821,6 +1576,7 @@ static inline int obd_unregister_lock_cancel_cb(struct obd_export *exp,
         rc = OBP(exp->exp_obd, unregister_lock_cancel_cb)(exp, cb);
         RETURN(rc);
 }
+#endif
 
 /* metadata helpers */
 static inline int md_getstatus(struct obd_export *exp,
index e72400a..b849ff0 100644 (file)
@@ -36,7 +36,7 @@
  * lustre/include/obd_ost.h
  *
  * Data structures for object storage targets and client: OST & OSC's
- * 
+ *
  * See also lustre_idl.h for wire formats of requests.
  */
 
@@ -54,21 +54,34 @@ struct osc_brw_async_args {
         struct brw_page  **aa_ppga;
         struct client_obd *aa_cli;
         struct list_head   aa_oaps;
+        struct cl_req     *aa_clerq;
 };
 
 struct osc_async_args {
         struct obd_info   *aa_oi;
 };
 
+struct osc_punch_args {
+        struct obdo         *pa_oa;
+        obd_enqueue_update_f pa_upcall;
+        void                *pa_cookie;
+};
+
 struct osc_enqueue_args {
-        struct obd_export       *oa_exp;
-        struct obd_info         *oa_oi;
-        struct ldlm_enqueue_info*oa_ei;
+        struct obd_export        *oa_exp;
+        int                      *oa_flags;
+        obd_enqueue_update_f      oa_upcall;
+        void                     *oa_cookie;
+        struct ost_lvb           *oa_lvb;
+        struct lustre_handle     *oa_lockh;
+        struct ldlm_enqueue_info *oa_ei;
 };
 
+#if 0
 int osc_extent_blocking_cb(struct ldlm_lock *lock,
                            struct ldlm_lock_desc *new, void *data,
                            int flag);
+#endif
 
 /** 
  * Build DLM resource name from object id & group for osc-ost extent lock.
index 2a8389d..25ab060 100644 (file)
@@ -77,6 +77,7 @@ extern unsigned int ldlm_timeout;         /* seconds */
 extern unsigned int obd_sync_filter;
 extern unsigned int obd_max_dirty_pages;
 extern atomic_t obd_dirty_pages;
+extern atomic_t obd_dirty_transit_pages;
 extern cfs_waitq_t obd_race_waitq;
 extern int obd_race_state;
 extern unsigned int obd_alloc_fail_rate;
index ceaaa20..b88a2bd 100644 (file)
@@ -1573,7 +1573,7 @@ Index: linux/MAINTAINERS
 ===================================================================
 --- linux.orig/MAINTAINERS
 +++ linux/MAINTAINERS
-@@ -1242,6 +1242,12 @@ W:      http://sf.net/projects/kernel-janitor
+@@ -1247,6 +1247,12 @@ W:      http://sf.net/projects/kernel-janitor
  W:    http://developer.osdl.org/rddunlap/kj-patches/
  S:    Maintained
  
@@ -1590,7 +1590,7 @@ Index: linux/arch/i386/Kconfig
 ===================================================================
 --- linux.orig/arch/i386/Kconfig
 +++ linux/arch/i386/Kconfig
-@@ -1250,6 +1250,14 @@ menu "Executable file formats"
+@@ -1292,6 +1292,14 @@ menu "Executable file formats"
  
  source "fs/Kconfig.binfmt"
  
@@ -1800,7 +1800,7 @@ Index: linux/arch/i386/Makefile
 ===================================================================
 --- linux.orig/arch/i386/Makefile
 +++ linux/arch/i386/Makefile
-@@ -98,6 +98,9 @@ core-$(CONFIG_X86_ES7000)    := arch/i386/m
+@@ -102,6 +102,9 @@ core-$(CONFIG_X86_ES7000)  := arch/i386/m
  # default subarch .h files
  mflags-y += -Iinclude/asm-i386/mach-default
  
@@ -1855,7 +1855,7 @@ Index: linux/arch/i386/kernel/entry.S
  
  #define __RESTORE_INT_REGS \
        popl %ebx;      \
-@@ -357,6 +370,7 @@ need_resched:
+@@ -361,6 +374,7 @@ need_resched:
        # sysenter call handler stub
  ENTRY(sysenter_entry)
        movl TSS_sysenter_esp0(%esp),%esp
@@ -1863,7 +1863,7 @@ Index: linux/arch/i386/kernel/entry.S
  sysenter_past_esp:
        sti
        pushl $(__USER_DS)
-@@ -437,6 +451,19 @@ syscall_exit:
+@@ -441,6 +455,19 @@ syscall_exit:
        testw $_TIF_ALLWORK_MASK, %cx   # current->work
        jne syscall_exit_work
  restore_all:
@@ -4382,7 +4382,7 @@ Index: linux/arch/i386/kernel/traps.c
                if (notify_die(DIE_GPF, "general protection fault", regs,
                                error_code, 13, SIGSEGV) == NOTIFY_STOP)
                        return;
-@@ -829,8 +874,18 @@ asmlinkage void do_debug(struct pt_regs 
+@@ -835,8 +880,18 @@ asmlinkage void do_debug(struct pt_regs 
                 * allowing programs to debug themselves without the ptrace()
                 * interface.
                 */
@@ -4401,7 +4401,7 @@ Index: linux/arch/i386/kernel/traps.c
                if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
                        goto clear_TF;
        }
-@@ -842,6 +897,17 @@ asmlinkage void do_debug(struct pt_regs 
+@@ -848,6 +903,17 @@ asmlinkage void do_debug(struct pt_regs 
        info.si_errno = 0;
        info.si_code = TRAP_BRKPT;
        
@@ -4419,7 +4419,7 @@ Index: linux/arch/i386/kernel/traps.c
        /* If this is a kernel mode trap, save the user PC on entry to 
         * the kernel, that's what the debugger can make sense of.
         */
-@@ -856,6 +922,7 @@ clear_dr7:
+@@ -862,6 +928,7 @@ clear_dr7:
        __asm__("movl %0,%%db7"
                : /* no output */
                : "r" (0));
@@ -4427,7 +4427,7 @@ Index: linux/arch/i386/kernel/traps.c
        return;
  
  debug_vm86:
-@@ -1151,6 +1218,12 @@ static void __init set_task_gate(unsigne
+@@ -1157,6 +1224,12 @@ static void __init set_task_gate(unsigne
  {
        _set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
  }
@@ -4440,7 +4440,7 @@ Index: linux/arch/i386/kernel/traps.c
  
  
  void __init trap_init(void)
-@@ -1169,7 +1242,11 @@ void __init trap_init(void)
+@@ -1175,7 +1248,11 @@ void __init trap_init(void)
        set_trap_gate(0,&divide_error);
        set_intr_gate(1,&debug);
        set_intr_gate(2,&nmi);
@@ -5051,7 +5051,7 @@ Index: linux/drivers/serial/8250.c
 ===================================================================
 --- linux.orig/drivers/serial/8250.c
 +++ linux/drivers/serial/8250.c
-@@ -880,7 +880,7 @@ receive_chars(struct uart_8250_port *up,
+@@ -882,7 +882,7 @@ receive_chars(struct uart_8250_port *up,
                if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
                        tty->flip.work.func((void *)tty);
                        if (tty->flip.count >= TTY_FLIPBUF_SIZE)
@@ -5060,7 +5060,7 @@ Index: linux/drivers/serial/8250.c
                }
                ch = serial_inp(up, UART_RX);
                *tty->flip.char_buf_ptr = ch;
-@@ -1241,12 +1241,21 @@ static void serial8250_break_ctl(struct 
+@@ -1245,12 +1245,21 @@ static void serial8250_break_ctl(struct 
        spin_unlock_irqrestore(&up->port.lock, flags);
  }
  
@@ -5082,7 +5082,7 @@ Index: linux/drivers/serial/8250.c
        up->capabilities = uart_config[up->port.type].flags;
        up->mcr = 0;
  
-@@ -1877,6 +1886,10 @@ static void __init serial8250_register_p
+@@ -1881,6 +1890,10 @@ static void __init serial8250_register_p
        for (i = 0; i < UART_NR; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
  
@@ -5093,7 +5093,7 @@ Index: linux/drivers/serial/8250.c
                up->port.line = i;
                up->port.ops = &serial8250_pops;
                init_timer(&up->timer);
-@@ -2160,6 +2173,31 @@ void serial8250_resume_port(int line)
+@@ -2181,6 +2194,31 @@ void serial8250_resume_port(int line)
        uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
  }
  
@@ -6317,20 +6317,12 @@ Index: linux/include/linux/spinlock.h
 +                SET_WHO(x, current)       \
        } while (0)
  
- /* without debugging, spin_is_locked on UP always says
-@@ -151,6 +162,7 @@ typedef struct {
-               (x)->lock = 1; \
-               (x)->owner = __FILE__; \
-               (x)->oline = __LINE__; \
-+                SET_WHO(x, current)       \
-               1; \
-       })
+ #define spin_is_locked(x) \
 Index: linux/kernel/pid.c
 ===================================================================
 --- linux.orig/kernel/pid.c
 +++ linux/kernel/pid.c
-@@ -276,6 +276,9 @@ int pid_alive(struct task_struct *p)
+@@ -320,6 +320,9 @@ struct pid *find_ge_pid(int nr)
   * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
   * more.
   */
@@ -6340,7 +6332,7 @@ Index: linux/kernel/pid.c
  void __init pidhash_init(void)
  {
        int i, j, pidhash_size;
-@@ -297,6 +300,9 @@ void __init pidhash_init(void)
+@@ -341,6 +344,9 @@ void __init pidhash_init(void)
                for (j = 0; j < pidhash_size; j++)
                        INIT_HLIST_HEAD(&pid_hash[i][j]);
        }
@@ -6354,7 +6346,7 @@ Index: linux/kernel/sched.c
 ===================================================================
 --- linux.orig/kernel/sched.c
 +++ linux/kernel/sched.c
-@@ -3190,6 +3190,13 @@ out_unlock:
+@@ -3207,6 +3207,13 @@ out_unlock:
  
  EXPORT_SYMBOL(set_user_nice);
  
diff --git a/lustre/kernel_patches/patches/2.6-rhel5-kgdb-ga.patch b/lustre/kernel_patches/patches/2.6-rhel5-kgdb-ga.patch
new file mode 100644 (file)
index 0000000..6e38859
--- /dev/null
@@ -0,0 +1,19200 @@
+diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/Documentation/DocBook/Makefile linux-2.6.18-53.1.14.kgdb/Documentation/DocBook/Makefile
+--- linux-2.6.18-53.1.14/Documentation/DocBook/Makefile        2008-03-06 05:54:50.000000000 +0300
++++ linux-2.6.18-53.1.14.kgdb/Documentation/DocBook/Makefile   2008-06-10 15:37:25.000000000 +0400
+@@ -11,7 +11,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mc
+           procfs-guide.xml writing_usb_driver.xml \
+           kernel-api.xml journal-api.xml lsm.xml utrace.xml usb.xml \
+           gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
+-          genericirq.xml
++          genericirq.xml kgdb.xml
+ ###
+ # The build process is as follows (targets):
+diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/Documentation/DocBook/kgdb.tmpl linux-2.6.18-53.1.14.kgdb/Documentation/DocBook/kgdb.tmpl
+--- linux-2.6.18-53.1.14/Documentation/DocBook/kgdb.tmpl       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-53.1.14.kgdb/Documentation/DocBook/kgdb.tmpl  2008-06-10 15:38:50.000000000 +0400
+@@ -0,0 +1,250 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
++      "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
++
++<book id="kgdbInternals">
++ <bookinfo>
++  <title>KGDB Internals</title>
++
++  <authorgroup>
++   <author>
++    <firstname>Tom</firstname>
++    <surname>Rini</surname>
++    <affiliation>
++     <address>
++      <email>trini@kernel.crashing.org</email>
++     </address>
++    </affiliation>
++   </author>
++  </authorgroup>
++
++  <authorgroup>
++   <author>
++    <firstname>Amit S.</firstname>
++    <surname>Kale</surname>
++    <affiliation>
++     <address>
++      <email>amitkale@linsyssoft.com</email>
++     </address>
++    </affiliation>
++   </author>
++  </authorgroup>
++
++  <copyright>
++   <year>2004-2005</year>
++   <holder>MontaVista Software, Inc.</holder>
++  </copyright>
++  <copyright>
++   <year>2004</year>
++   <holder>Amit S. Kale</holder>
++  </copyright>
++
++  <legalnotice>
++   <para>
++   This file is licensed under the terms of the GNU General Public License
++   version 2. This program is licensed "as is" without any warranty of any
++   kind, whether express or implied.
++   </para>
++
++  </legalnotice>
++ </bookinfo>
++
++<toc></toc>
++  <chapter id="Introduction">
++    <title>Introduction</title>
++    <para>
++    kgdb is a source level debugger for linux kernel. It is used along
++    with gdb to debug a linux kernel. Kernel developers can debug a kernel
++    similar to application programs with the use of kgdb. It makes it
++    possible to place breakpoints in kernel code, step through the code
++    and observe variables.
++    </para>
++    <para>
++    Two machines are required for using kgdb. One of these machines is a
++    development machine and the other is a test machine. The machines are
++    typically connected through a serial line, a null-modem cable which
++    connects their serial ports.  It is also possible however, to use an
++    ethernet connection between the machines.  The kernel to be debugged
++    runs on the test machine. gdb runs on the development machine. The
++    serial line or ethernet connection is used by gdb to communicate to
++    the kernel being debugged.
++    </para>
++  </chapter>
++  <chapter id="CompilingAKernel">
++    <title>Compiling a kernel</title>
++    <para>
++    To enable <symbol>CONFIG_KGDB</symbol>, look under the "Kernel debugging"
++    and then select "KGDB: kernel debugging with remote gdb".
++    </para>
++    <para>
++    The first choice for I/O is <symbol>CONFIG_KGDB_ONLY_MODULES</symbol>.
++    This means that you will only be able to use KGDB after loading a
++    kernel module that defines how you want to be able to talk with
++    KGDB.  There are two other choices (more on some architectures) that
++    can be enabled as modules later, if not picked here.
++    </para>
++    <para>The first of these is <symbol>CONFIG_KGDB_8250_NOMODULE</symbol>.
++    This has sub-options such as <symbol>CONFIG_KGDB_SIMPLE_SERIAL</symbol>
++    which toggles choosing the serial port by ttyS number or by specifying
++    a port and IRQ number.
++    </para>
++    <para>
++    The second of these choices on most systems for I/O is
++    <symbol>CONFIG_KGDBOE</symbol>. This requires that the machine to be
++    debugged has an ethernet card which supports the netpoll API, such as
++    the cards supported by <symbol>CONFIG_E100</symbol>.  There are no
++    sub-options for this, but a kernel command line option is required.
++    </para>
++  </chapter>
++  <chapter id="BootingTheKernel">
++    <title>Booting the kernel</title>
++    <para>
++    The Kernel command line option <constant>kgdbwait</constant> makes kgdb
++    wait for gdb connection during booting of a kernel.  If the
++    <symbol>CONFIG_KGDB_8250</symbol> driver is used (or if applicable,
++    another serial driver) this breakpoint will happen very early on, before
++    console output.  If you wish to change serial port information and you
++    have enabled both <symbol>CONFIG_KGDB_8250</symbol> and
++    <symbol>CONFIG_KGDB_SIMPLE_SERIAL</symbol> then you must pass the option
++    <constant>kgdb8250=&lt;io or mmio&gt;,&lt;address&gt;,&lt;baud
++    rate&gt;,&lt;irq&gt;</constant> before <constant>kgdbwait</constant>.
++    The values <constant>io</constant> or <constant>mmio</constant> refer to
++    if the address being passed next needs to be memory mapped
++    (<constant>mmio</constant>) or not. The <constant>address</constant> must
++    be passed in hex and is the hardware address and will be remapped if
++    passed as <constant>mmio</constant>. The value
++    <constant>baud rate</constant> and <constant>irq</constant> are base-10.
++    The supported values for <constant>baud rate</constant> are
++    <constant>9600</constant>, <constant>19200</constant>,
++    <constant>38400</constant>, <constant>57600</constant>, and
++    <constant>115200</constant>.
++    </para>
++    <para>
++    To have KGDB stop the kernel and wait, with the compiled values for the
++    serial driver, pass in: <constant>kgdbwait</constant>.
++    </para>
++    <para>
++    To specify the values of the SH SCI(F) serial port at boot:
++    <constant>kgdbsci=0,115200</constant>.
++    </para>
++    <para>
++    To specify the values of the serial port at boot:
++    <constant>kgdb8250=io,3f8,115200,3</constant>.
++    On IA64 this could also be:
++    <constant>kgdb8250=mmio,0xff5e0000,115200,74</constant>
++    And to have KGDB also stop the kernel and wait for GDB to connect, pass in
++    <constant>kgdbwait</constant> after this arguement.
++    </para>
++    <para>
++    To configure the <symbol>CONFIG_KGDBOE</symbol> driver, pass in
++    <constant>kgdboe=[src-port]@&lt;src-ip&gt;/[dev],[tgt-port]@&lt;tgt-ip&gt;/[tgt-macaddr]</constant>
++    where:
++    <itemizedlist>
++      <listitem><para>src-port (optional): source for UDP packets (defaults to <constant>6443</constant>)</para></listitem>
++      <listitem><para>src-ip: source IP to use (interface address)</para></listitem>
++      <listitem><para>dev (optional): network interface (<constant>eth0</constant>)</para></listitem>
++      <listitem><para>tgt-port (optional): port GDB will use (defaults to <constant>6442</constant>)</para></listitem>
++      <listitem><para>tgt-ip: IP address GDB will be connecting from</para></listitem>
++      <listitem><para>tgt-macaddr (optional): ethernet MAC address for logging agent (default is broadcast)</para></listitem>
++    </itemizedlist>
++    </para>
++    <para>
++    The <symbol>CONFIG_KGDBOE</symbol> driver can be reconfigured at run
++    time, if <symbol>CONFIG_SYSFS</symbol> and
++    <symbol>CONFIG_MODULES</symbol> by echo'ing a new config string to
++    <constant>/sys/module/kgdboe/parameter/kgdboe</constant>.  The
++    driver can be unconfigured with the special string
++    <constant>not_configured</constant>.
++    </para>
++  </chapter>
++  <chapter id="ConnectingGDB">
++  <title>Connecting gdb</title>
++    <para>
++    If you have used any of the methods to have KGDB stop and create
++    an initial breakpoint described in the previous chapter, kgdb prints
++    the message "Waiting for connection from remote gdb..." on the console
++    and waits for connection from gdb. At this point you connect gdb to kgdb.
++    </para>
++    <para>
++    Example (serial):
++    </para>
++    <programlisting>
++    % gdb ./vmlinux
++    (gdb) set remotebaud 115200
++    (gdb) target remote /dev/ttyS0
++    </programlisting>
++    <para>
++    Example (ethernet):
++    </para>
++    <programlisting>
++    % gdb ./vmlinux
++    (gdb) target remote udp:192.168.2.2:6443
++    </programlisting>
++    <para>
++    Once connected, you can debug a kernel the way you would debug an
++    application program.
++    </para>
++  </chapter>
++  <chapter id="ArchitectureNotes">
++    <title>Architecture specific notes</title>
++      <para>
++      SuperH: The NMI switch found on some boards can be used to trigger an
++      initial breakpoint.  Subsequent triggers do nothing.  If console
++      is enabled on the SCI(F) serial port, and that is the port being used
++      for KGDB, then you must trigger a breakpoint via sysrq, NMI, or
++      some other method prior to connecting, or echo a control-c to the
++      serial port.  Also, to use the SCI(F) port for KGDB, the
++      <symbol>CONFIG_SERIAL_SH_SCI</symbol> driver must be enabled.
++      </para>
++  </chapter>
++  <chapter id="CommonBackEndReq">
++    <title>The common backend (required)</title>
++      <para>
++      There are a few flags which must be set on every architecture in
++      their &lt;asm/kgdb.h&gt; file.  These are:
++      <itemizedlist>
++        <listitem>
++        <para>
++        NUMREGBYTES: The size in bytes of all of the registers, so
++        that we can ensure they will all fit into a packet.
++        </para>
++        <para>
++        BUFMAX: The size in bytes of the buffer GDB will read into.
++        This must be larger than NUMREGBYTES.
++        </para>
++        <para>
++        CACHE_FLUSH_IS_SAFE: Set to one if it always safe to call
++        flush_cache_range or flush_icache_range.  On some architectures,
++        these functions may not be safe to call on SMP since we keep other
++        CPUs in a holding pattern.
++        </para>
++      </listitem>
++      </itemizedlist>
++      </para>
++      <para>
++      There are also the following functions for the common backend,
++      found in kernel/kgdb.c that must be supplied by the
++      architecture-specific backend.  No weak version of these is provided.
++      </para>
++!Iinclude/linux/kgdb.h
++  </chapter>
++  <chapter id="CommonBackEndOpt">
++    <title>The common backend (optional)</title>
++      <para>
++      These functions are part of the common backend, found in kernel/kgdb.c
++      and are optionally implemented.  Some functions (with _hw_ in the name)
++      end up being required on arches which use hardware breakpoints.
++      </para>
++!Ikernel/kgdb.c
++  </chapter>
++  <chapter id="DriverSpecificFunctions">
++    <title>Driver-Specific Functions</title>
++      <para>
++      Some of the I/O drivers have additional functions that can be
++      called, that are specific to the driver.  Calls from other places
++      to these functions must be wrapped in #ifdefs for the driver in
++      question.
++      </para>
++!Idrivers/serial/8250_kgdb.c
++   </chapter>
++</book>
+diff -rupbBN -X ../client-cleanup/dontdiff linux-2.6.18-53.1.14/MAINTAINERS linux-2.6.18-53.1.14.kgdb/MAINTAINERS
+--- linux-2.6.18-53.1.14/MAINTAINERS   2008-03-06 05:54:49.000000000 +0