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;
};
/**
* \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 whether the page contains valid data or not by @uptodate.
+ * Announces whether the page contains valid data or not by \a uptodate.
*
* \see cl_page_export()
* \see vvp_page_export()
* | | 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
};
/**
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
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()
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.
*/
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,
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,
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_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,
/** 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;
+ cfs_waitq_t csi_waitq;
/** 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);
+ 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
* @{ */