-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
+/*
* GPL HEADER START
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* GPL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2012, Whamcloud, Inc.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*/
/** @{ */
/** Lock protecting page tree. */
- spinlock_t coh_page_guard;
+ cfs_spinlock_t coh_page_guard;
/** Lock protecting lock list. */
- spinlock_t coh_lock_guard;
+ cfs_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;
+ cfs_list_t coh_locks;
/**
* Parent object. It is assumed that an object has a well-defined
*
* \todo XXX this can be read/write lock if needed.
*/
- spinlock_t coh_attr_guard;
+ cfs_spinlock_t coh_attr_guard;
/**
* Number of objects above this one: 0 for a top-object, 1 for its
* sub-object, etc.
* 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)
+#define cl_object_for_each(slice, obj) \
+ cfs_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)
+#define cl_object_for_each_reverse(slice, obj) \
+ cfs_list_for_each_entry_reverse((slice), \
+ &(obj)->co_lu.lo_header->loh_layers, \
+ co_lu.lo_linkage)
/** @} cl_object */
#ifndef pgoff_t
*/
struct cl_page {
/** Reference counter. */
- atomic_t cp_ref;
+ cfs_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;
+ cfs_list_t 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
/**
* Linkage of pages within some group. Protected by
* cl_page::cp_mutex. */
- struct list_head cp_batch;
+ cfs_list_t cp_batch;
/** Mutex serializing membership of a page in a batch. */
- struct mutex cp_mutex;
+ cfs_mutex_t cp_mutex;
/** Linkage of pages within cl_req. */
- struct list_head cp_flight;
+ cfs_list_t cp_flight;
/** Transfer error. */
int cp_error;
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;
+ cfs_list_t cpl_linkage;
};
/**
*/
int (*cpo_cancel)(const struct lu_env *env,
const struct cl_page_slice *slice);
+ /**
+ * Write out a page by kernel. This is only called by ll_writepage
+ * right now.
+ *
+ * \see cl_page_flush()
+ */
+ int (*cpo_flush)(const struct lu_env *env,
+ const struct cl_page_slice *slice,
+ struct cl_io *io);
/** @} transfer */
};
*/
#define CL_PAGE_DEBUG(mask, env, page, format, ...) \
do { \
- static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask); \
+ LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, mask, NULL); \
\
- if (cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
- cl_page_print(env, &__info, lu_cdebug_printer, page); \
+ if (cfs_cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
+ cl_page_print(env, &msgdata, 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__); \
- } \
+#define CL_PAGE_HEADER(mask, env, page, format, ...) \
+do { \
+ LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, mask, NULL); \
+ \
+ if (cfs_cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
+ cl_page_header_print(env, &msgdata, lu_cdebug_printer, page); \
+ CDEBUG(mask, format , ## __VA_ARGS__); \
+ } \
} while (0)
/** @} cl_page */
/** cancellation is pending for this lock. */
CLF_CANCELPEND = 1 << 1,
/** destruction is pending for this lock. */
- CLF_DOOMED = 1 << 2
+ CLF_DOOMED = 1 << 2,
+ /** from enqueue RPC reply upcall. */
+ CLF_FROM_UPCALL= 1 << 3,
};
/**
* List of enclosed locks, so far. Locks are linked here through
* cl_lock::cll_inclosure.
*/
- struct list_head clc_list;
+ cfs_list_t 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
*/
struct cl_lock {
/** Reference counter. */
- atomic_t cll_ref;
+ cfs_atomic_t cll_ref;
/** List of slices. Immutable after creation. */
- struct list_head cll_layers;
+ cfs_list_t 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;
+ cfs_list_t cll_linkage;
/**
* Parameters of this lock. Protected by
* cl_lock::cll_descr::cld_obj::coh_lock_guard nested within
*
* \see osc_lock_enqueue_wait(), lov_lock_cancel(), lov_sublock_wait().
*/
- struct mutex cll_guard;
+ cfs_mutex_t cll_guard;
cfs_task_t *cll_guarder;
int cll_depth;
*
* \see cl_lock_closure
*/
- struct list_head cll_inclosure;
+ cfs_list_t cll_inclosure;
/**
* Confict lock at queuing time.
*/
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;
+ cfs_list_t cls_linkage;
};
/**
*/
enum cl_lock_transition {
/** operation cannot be completed immediately. Wait for state change. */
- CLO_WAIT = 1,
+ CLO_WAIT = 1,
/** operation had to release lock mutex, restart. */
- CLO_REPEAT = 2
+ CLO_REPEAT = 2,
+ /** lower layer re-enqueued. */
+ CLO_REENQUEUED = 3,
};
/**
#define CL_LOCK_DEBUG(mask, env, lock, format, ...) \
do { \
- static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask); \
+ LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, mask, NULL); \
\
- if (cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
- cl_lock_print(env, &__info, lu_cdebug_printer, lock); \
+ if (cfs_cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
+ cl_lock_print(env, &msgdata, lu_cdebug_printer, lock); \
CDEBUG(mask, format , ## __VA_ARGS__); \
} \
} while (0)
+#define CL_LOCK_ASSERT(expr, env, lock) do { \
+ if (likely(expr)) \
+ break; \
+ \
+ CL_LOCK_DEBUG(D_ERROR, env, lock, "failed at %s.\n", #expr); \
+ LBUG(); \
+} while (0)
+
/** @} cl_lock */
/** \addtogroup cl_page_list cl_page_list
* @{
*/
struct cl_page_list {
- unsigned pl_nr;
- struct list_head pl_pages;
- cfs_task_t *pl_owner;
+ unsigned pl_nr;
+ cfs_list_t pl_pages;
+ cfs_task_t *pl_owner;
};
/**
CIT_READ,
/** write system call */
CIT_WRITE,
- /** truncate system call */
- CIT_TRUNC,
+ /** truncate, utime system calls */
+ CIT_SETATTR,
/**
* page fault handling
*/
CIT_FAULT,
/**
+ * fsync system call handling
+ * To write out a range of file
+ */
+ CIT_FSYNC,
+ /**
* Miscellaneous io. This is used for occasional io activity that
* doesn't fit into other types. Currently this is used for:
*
CIS_FINI
};
-enum cl_req_priority {
- CRP_NORMAL,
- CRP_CANCEL
-};
-
/**
* IO state private for a layer.
*
* 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;
+ cfs_list_t cis_linkage;
};
int (*cio_submit)(const struct lu_env *env,
const struct cl_io_slice *slice,
enum cl_req_type crt,
- struct cl_2queue *queue,
- enum cl_req_priority priority);
+ struct cl_2queue *queue);
} req_op[CRT_NR];
/**
* Read missing page.
*/
CEF_NEVER = 0x00000010,
/**
+ * for async glimpse lock.
+ */
+ CEF_AGL = 0x00000020,
+ /**
* mask of enq_flags.
*/
- CEF_MASK = 0x0000001f
+ CEF_MASK = 0x0000003f,
};
/**
*/
struct cl_io_lock_link {
/** linkage into one of cl_lockset lists. */
- struct list_head cill_linkage;
+ cfs_list_t cill_linkage;
struct cl_lock_descr cill_descr;
struct cl_lock *cill_lock;
/** optional destructor */
*/
struct cl_lockset {
/** locks to be acquired. */
- struct list_head cls_todo;
+ cfs_list_t cls_todo;
/** locks currently being processed. */
- struct list_head cls_curr;
+ cfs_list_t cls_curr;
/** locks acquired. */
- struct list_head cls_done;
+ cfs_list_t cls_done;
};
/**
/** Layers are free to decide between local and global locking. */
CILR_MAYBE,
/** Never lock: there is no cache (e.g., liblustre). */
- CILR_NEVER
+ CILR_NEVER,
+ /** Peek lock: use existing locks, don't queue new ones */
+ CILR_PEEK
+};
+
+enum cl_fsync_mode {
+ /** start writeback, do not wait for them to finish */
+ CL_FSYNC_NONE = 0,
+ /** start writeback and wait for them to finish */
+ CL_FSYNC_LOCAL = 1,
+ /** discard all of dirty pages in a specific file range */
+ CL_FSYNC_DISCARD = 2,
+ /** start writeback and make sure they have reached storage before
+ * return. OST_SYNC RPC must be issued and finished */
+ CL_FSYNC_ALL = 3
};
struct cl_io_rw_common {
*/
struct cl_io *ci_parent;
/** List of slices. Immutable after creation. */
- struct list_head ci_layers;
+ cfs_list_t 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. */
struct cl_wr_io {
struct cl_io_rw_common wr;
int wr_append;
+ int wr_sync;
} 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_setattr_io {
+ struct ost_lvb sa_attr;
+ unsigned int sa_valid;
+ struct obd_capa *sa_capa;
+ } ci_setattr;
struct cl_fault_io {
/** page index within file. */
pgoff_t ft_index;
/** bytes valid byte on a faulted page. */
int ft_nob;
- /** writable page? */
+ /** writable page? for nopage() only */
int ft_writable;
/** page of an executable? */
int ft_executable;
+ /** page_mkwrite() */
+ int ft_mkwrite;
/** resulting page */
struct cl_page *ft_page;
} ci_fault;
+ struct cl_fsync_io {
+ loff_t fi_start;
+ loff_t fi_end;
+ struct obd_capa *fi_capa;
+ /** file system level fid */
+ struct lu_fid *fi_fid;
+ enum cl_fsync_mode fi_mode;
+ /* how many pages were written/discarded */
+ unsigned int fi_nr_written;
+ } ci_fsync;
} u;
struct cl_2queue ci_queue;
size_t ci_nob;
* Per-transfer attributes.
*/
struct cl_req_attr {
- /** Generic attributes for the server consumption. */
- struct obdo *cra_oa;
- /** Capability. */
- struct obd_capa *cra_capa;
+ /** Generic attributes for the server consumption. */
+ struct obdo *cra_oa;
+ /** Capability. */
+ struct obd_capa *cra_capa;
+ /** Jobid */
+ char cra_jobid[JOBSTATS_JOBID_SIZE];
};
/**
* req's pages.
*/
struct cl_req {
- enum cl_req_type crq_type;
+ enum cl_req_type crq_type;
/** A list of pages being transfered */
- struct list_head crq_pages;
+ cfs_list_t crq_pages;
/** Number of pages in cl_req::crq_pages */
- unsigned crq_nrpages;
+ unsigned crq_nrpages;
/** An array of objects which pages are in ->crq_pages */
- struct cl_req_obj *crq_o;
+ struct cl_req_obj *crq_o;
/** Number of elements in cl_req::crq_objs[] */
- unsigned crq_nrobjs;
- struct list_head crq_layers;
+ unsigned crq_nrobjs;
+ cfs_list_t crq_layers;
};
/**
struct cl_req_slice {
struct cl_req *crs_req;
struct cl_device *crs_dev;
- struct list_head crs_linkage;
+ cfs_list_t crs_linkage;
const struct cl_req_operations *crs_ops;
};
struct cache_stats {
const char *cs_name;
/** how many entities were created at all */
- atomic_t cs_created;
+ cfs_atomic_t cs_created;
/** how many cache lookups were performed */
- atomic_t cs_lookup;
+ cfs_atomic_t cs_lookup;
/** how many times cache lookup resulted in a hit */
- atomic_t cs_hit;
+ cfs_atomic_t cs_hit;
/** how many entities are in the cache right now */
- atomic_t cs_total;
+ cfs_atomic_t cs_total;
/** how many entities in the cache are actively used (and cannot be
* evicted) right now */
- atomic_t cs_busy;
+ cfs_atomic_t cs_busy;
};
/** These are not exported so far */
*/
struct cache_stats cs_pages;
struct cache_stats cs_locks;
- atomic_t cs_pages_state[CPS_NR];
- atomic_t cs_locks_state[CLS_NR];
+ cfs_atomic_t cs_pages_state[CPS_NR];
+ cfs_atomic_t cs_locks_state[CLS_NR];
};
int cl_site_init (struct cl_site *s, struct cl_device *top);
/** \defgroup cl_page cl_page
* @{ */
-struct cl_page *cl_page_lookup(struct cl_object_header *hdr,
+enum {
+ CLP_GANG_OKAY = 0,
+ CLP_GANG_RESCHED,
+ CLP_GANG_AGAIN,
+ CLP_GANG_ABORT
+};
+
+/* callback of cl_page_gang_lookup() */
+typedef int (*cl_page_gang_cb_t) (const struct lu_env *, struct cl_io *,
+ struct cl_page *, void *);
+int cl_page_gang_lookup (const struct lu_env *env,
+ struct cl_object *obj,
+ struct cl_io *io,
+ pgoff_t start, pgoff_t end,
+ cl_page_gang_cb_t cb, void *cbdata);
+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,
- int nonblock);
struct cl_page *cl_page_find (const struct lu_env *env,
struct cl_object *obj,
pgoff_t idx, struct page *vmpage,
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);
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);
+int cl_page_flush (const struct lu_env *env, struct cl_io *io,
+ struct cl_page *pg);
/** @} transfer */
struct cl_lock *cl_lock_request(const struct lu_env *env, struct cl_io *io,
const struct cl_lock_descr *need,
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);
+struct cl_lock *cl_lock_at_pgoff(const struct lu_env *env,
+ struct cl_object *obj, pgoff_t index,
+ struct cl_lock *except, int pending,
+ int canceld);
+static inline 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)
+{
+ return cl_lock_at_pgoff(env, obj, page->cp_index, except,
+ pending, canceld);
+}
const struct cl_lock_slice *cl_lock_at(const struct cl_lock *lock,
const struct lu_device_type *dtype);
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);
+void cl_lock_user_del (const struct lu_env *env, struct cl_lock *lock);
enum cl_lock_state cl_lock_intransit(const struct lu_env *env,
struct cl_lock *lock);
-
void cl_lock_extransit(const struct lu_env *env, struct cl_lock *lock,
enum cl_lock_state state);
-
int cl_lock_is_intransit(struct cl_lock *lock);
+int cl_lock_enqueue_wait(const struct lu_env *env, struct cl_lock *lock,
+ int keep_mutex);
+
/** \name statemachine statemachine
* Interface to lock state machine consists of 3 parts:
*
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, int atomic);
+
/** @} 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,
+int cl_queue_match (const cfs_list_t *queue,
const struct cl_lock_descr *need);
void cl_lock_mutex_get (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_discard_pages(const struct lu_env *env, struct cl_lock *lock);
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,
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);
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,
- enum cl_req_priority priority);
+ enum cl_req_type iot, struct cl_2queue *queue);
int cl_io_submit_sync (const struct lu_env *env, struct cl_io *io,
- enum cl_req_type iot, struct cl_2queue *queue,
- enum cl_req_priority priority, long timeout);
+ enum cl_req_type iot, struct cl_2queue *queue,
+ long timeout);
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,
return io->ci_type == CIT_WRITE && io->u.ci_wr.wr_append;
}
+static inline int cl_io_is_sync_write(const struct cl_io *io)
+{
+ return io->ci_type == CIT_WRITE && io->u.ci_wr.wr_sync;
+}
+
+static inline int cl_io_is_mkwrite(const struct cl_io *io)
+{
+ return io->ci_type == CIT_FAULT && io->u.ci_fault.ft_mkwrite;
+}
+
+/**
+ * True, iff \a io is a truncate(2).
+ */
+static inline int cl_io_is_trunc(const struct cl_io *io)
+{
+ return io->ci_type == CIT_SETATTR &&
+ (io->u.ci_setattr.sa_valid & ATTR_SIZE);
+}
+
struct cl_io *cl_io_top(struct cl_io *io);
void cl_io_print(const struct lu_env *env, void *cookie,
* @{ */
/**
+ * Last page in the page list.
+ */
+static inline struct cl_page *cl_page_list_last(struct cl_page_list *plist)
+{
+ LASSERT(plist->pl_nr > 0);
+ return cfs_list_entry(plist->pl_pages.prev, struct cl_page, cp_batch);
+}
+
+/**
* 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)
+ cfs_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)
+ cfs_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);
*/
struct cl_sync_io {
/** number of pages yet to be transferred. */
- atomic_t csi_sync_nr;
+ cfs_atomic_t csi_sync_nr;
/** completion to be signaled when transfer is complete. */
cfs_waitq_t csi_waitq;
/** error code. */
- int csi_sync_rc;
+ int csi_sync_rc;
};
void cl_sync_io_init(struct cl_sync_io *anchor, int nrpages);