*/
/** @{ */
/** 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_io *cp_owner;
/**
+ * Debug information, the task is owning the page.
+ */
+ cfs_task_t *cp_task;
+ /**
* 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 lu_ref_link *cp_queue_ref;
/** Per-page flags from enum cl_page_flags. Protected by a VM lock. */
unsigned cp_flags;
+ /** Assigned if doing a sync_io */
+ struct cl_sync_io *cp_sync_io;
};
/**
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;
};
/**
* \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);
+ int (*cpo_own)(const struct lu_env *env,
+ const struct cl_page_slice *slice,
+ struct cl_io *io, int nonblock);
/** Called when ownership it yielded. Optional.
*
* \see cl_page_disown()
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.
+ * Announces whether the page contains valid data or not by \a uptodate.
*
* \see cl_page_export()
* \see vvp_page_export()
*/
void (*cpo_export)(const struct lu_env *env,
- const struct cl_page_slice *slice);
+ const struct cl_page_slice *slice, int uptodate);
/**
* Unmaps page from the user space (if it is mapped).
*
do { \
static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask); \
\
- if (cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
+ if (cfs_cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
cl_page_print(env, &__info, lu_cdebug_printer, page); \
CDEBUG(mask, format , ## __VA_ARGS__); \
} \
do { \
static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask); \
\
- if (cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
+ if (cfs_cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
cl_page_header_print(env, &__info, lu_cdebug_printer, page); \
CDEBUG(mask, format , ## __VA_ARGS__); \
} \
__u64 cld_gid;
/** Lock mode. */
enum cl_lock_mode cld_mode;
+ /**
+ * flags to enqueue lock. A combination of bit-flags from
+ * enum cl_enq_flags.
+ */
+ __u32 cld_enq_flags;
};
#define DDESCR "%s(%d):[%lu, %lu]"
* | | V
* | | HELD<---------+
* | | | |
- * | | | |
+ * | | | | cl_use_try()
* | | cl_unuse_try() | |
* | | | |
- * | | V | cached
- * | +------------>UNLOCKING (*) | lock found
- * | | |
- * | cl_unuse_try() | |
+ * | | V ---+
+ * | +------------>INTRANSIT (D) <--+
* | | |
+ * | cl_unuse_try() | | cached lock found
* | | | cl_use_try()
+ * | | |
* | V |
* +------------------CACHED---------+
* |
*
* (C) is the point where Cancellation call-back is invoked.
*
+ * (D) is the transit state which means the lock is changing.
+ *
* Transition to FREEING state is possible from any other state in the
* diagram in case of unrecoverable error.
* </pre>
* 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 {
/**
*/
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.
+ * This state is used to mark the lock is being used, or unused.
+ * We need this state because the lock may have several sublocks,
+ * so it's impossible to have an atomic way to bring all sublocks
+ * into CLS_HELD state at use case, or all sublocks to CLS_CACHED
+ * at unuse case.
+ * If a thread is referring to a lock, and it sees the lock is in this
+ * state, it must wait for the lock.
+ * See state diagram for details.
*/
- CLS_UNLOCKING,
+ CLS_INTRANSIT,
/**
* Lock granted, not used.
*/
/** 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
+ CLF_DOOMED = 1 << 2
};
/**
* 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;
+ /**
+ * the owner for INTRANSIT state
+ */
+ cfs_task_t *cll_intransit_owner;
int cll_error;
/**
* Number of holds on a lock. A hold prevents a lock from being
*
* \see cl_lock_closure
*/
- struct list_head cll_inclosure;
+ cfs_list_t cll_inclosure;
+ /**
+ * Confict lock at queuing time.
+ */
+ struct cl_lock *cll_conflict;
/**
* A list of references to this lock, for debugging.
*/
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;
};
/**
* 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.
+ * unuse is a one-shot operation, so it must NOT return CLO_WAIT.
*
- * \see ccc_lock_unlock(), lov_lock_unlock(), osc_lock_unlock()
+ * \see ccc_lock_unuse(), lov_lock_unuse(), osc_lock_unuse()
*/
int (*clo_unuse)(const struct lu_env *env,
const struct cl_lock_slice *slice);
const struct cl_lock_slice *slice,
struct cl_lock_closure *closure);
/**
- * Executed top-to-bottom when lock description changes (e.g., as a
+ * Executed bottom-to-top when lock description changes (e.g., as a
* result of server granting more generous lock than was requested).
*
* \see lovsub_lock_modify()
do { \
static DECLARE_LU_CDEBUG_PRINT_INFO(__info, mask); \
\
- if (cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
+ if (cfs_cdebug_show(mask, DEBUG_SUBSYSTEM)) { \
cl_lock_print(env, &__info, lu_cdebug_printer, lock); \
CDEBUG(mask, format , ## __VA_ARGS__); \
} \
* @{
*/
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;
};
-/** \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.
*/
* 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;
};
*/
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;
- /**
- * 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);
*/
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;
};
/**
int crw_nonblock;
};
+
/**
* State for io.
*
*/
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. */
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;
* 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);
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);
+int cl_object_has_locks (struct cl_object *obj);
/**
* Returns true, iff \a o0 and \a o1 are slices of the same object.
struct cl_object *obj,
struct cl_io *io,
pgoff_t start, pgoff_t end,
- struct cl_page_list *plist);
+ 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,
enum cl_page_type type);
+struct cl_page *cl_page_find_sub (const struct lu_env *env,
+ struct cl_object *obj,
+ pgoff_t idx, struct page *vmpage,
+ struct cl_page *parent);
void cl_page_get (struct cl_page *page);
void cl_page_put (const struct lu_env *env,
struct cl_page *page);
int cl_page_own (const struct lu_env *env,
struct cl_io *io, struct cl_page *page);
+int cl_page_own_try (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_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);
+void cl_page_export (const struct lu_env *env,
+ struct cl_page *pg, int uptodate);
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);
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,
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);
+
+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);
/** \name statemachine statemachine
* Interface to lock state machine consists of 3 parts:
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);
+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);
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 enqflags);
+ 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,
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);
+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);
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;
}
-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,
* 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. */
- struct completion csi_sync_completion;
+ 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);
int cl_sync_io_wait(const struct lu_env *env, struct cl_io *io,
- struct cl_page_list *queue, struct cl_sync_io *anchor);
+ struct cl_page_list *queue, struct cl_sync_io *anchor,
+ long timeout);
void cl_sync_io_note(struct cl_sync_io *anchor, int ioret);
/** @} cl_sync_io */
* 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.
+ * data structure representing current thread 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.
+ * Right now, three interfaces can attach the cl_env to running thread:
+ * - cl_env_get
+ * - cl_env_implant
+ * - cl_env_reexit(cl_env_reenter had to be called priorly)
*
* \see lu_env, lu_context, lu_context_key
* @{ */