struct ptlrpc_request;
struct obd_device;
-/**
- * Serializes in-flight MDT-modifying RPC requests to preserve idempotency.
- *
- * This mutex is used to implement execute-once semantics on the MDT.
- * The MDT stores the last transaction ID and result for every client in
- * its last_rcvd file. If the client doesn't get a reply, it can safely
- * resend the request and the MDT will reconstruct the reply being aware
- * that the request has already been executed. Without this lock,
- * execution status of concurrent in-flight requests would be
- * overwritten.
- *
- * This design limits the extent to which we can keep a full pipeline of
- * in-flight requests from a single client. This limitation could be
- * overcome by allowing multiple slots per client in the last_rcvd file.
- */
-struct mdc_rpc_lock {
- /** Lock protecting in-flight RPC concurrency. */
- struct mutex rpcl_mutex;
- /** Intent associated with currently executing request. */
- struct lookup_intent *rpcl_it;
- /** Used for MDS/RPC load testing purposes. */
- int rpcl_fakes;
-};
-
-#define MDC_FAKE_RPCL_IT ((void *)0x2c0012bfUL)
-
-static inline void mdc_init_rpc_lock(struct mdc_rpc_lock *lck)
-{
- mutex_init(&lck->rpcl_mutex);
- lck->rpcl_it = NULL;
-}
-
-static inline void mdc_get_rpc_lock(struct mdc_rpc_lock *lck,
- struct lookup_intent *it)
-{
- ENTRY;
-
- if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP ||
- it->it_op == IT_LAYOUT || it->it_op == IT_READDIR))
- return;
-
- /* This would normally block until the existing request finishes.
- * If fail_loc is set it will block until the regular request is
- * done, then set rpcl_it to MDC_FAKE_RPCL_IT. Once that is set
- * it will only be cleared when all fake requests are finished.
- * Only when all fake requests are finished can normal requests
- * be sent, to ensure they are recoverable again. */
- again:
- mutex_lock(&lck->rpcl_mutex);
-
- if (CFS_FAIL_CHECK_QUIET(OBD_FAIL_MDC_RPCS_SEM)) {
- lck->rpcl_it = MDC_FAKE_RPCL_IT;
- lck->rpcl_fakes++;
- mutex_unlock(&lck->rpcl_mutex);
- return;
- }
-
- /* This will only happen when the CFS_FAIL_CHECK() was
- * just turned off but there are still requests in progress.
- * Wait until they finish. It doesn't need to be efficient
- * in this extremely rare case, just have low overhead in
- * the common case when it isn't true. */
- while (unlikely(lck->rpcl_it == MDC_FAKE_RPCL_IT)) {
- mutex_unlock(&lck->rpcl_mutex);
- schedule_timeout(cfs_time_seconds(1) / 4);
- goto again;
- }
-
- LASSERT(lck->rpcl_it == NULL);
- lck->rpcl_it = it;
-}
-
-static inline void mdc_put_rpc_lock(struct mdc_rpc_lock *lck,
- struct lookup_intent *it)
-{
- if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP ||
- it->it_op == IT_LAYOUT || it->it_op == IT_READDIR))
- goto out;
-
- if (lck->rpcl_it == MDC_FAKE_RPCL_IT) { /* OBD_FAIL_MDC_RPCS_SEM */
- mutex_lock(&lck->rpcl_mutex);
-
- LASSERTF(lck->rpcl_fakes > 0, "%d\n", lck->rpcl_fakes);
- lck->rpcl_fakes--;
-
- if (lck->rpcl_fakes == 0)
- lck->rpcl_it = NULL;
-
- } else {
- LASSERTF(it == lck->rpcl_it, "%p != %p\n", it, lck->rpcl_it);
- lck->rpcl_it = NULL;
- }
-
- mutex_unlock(&lck->rpcl_mutex);
- out:
- EXIT;
-}
-
static inline void mdc_get_mod_rpc_slot(struct ptlrpc_request *req,
struct lookup_intent *it)
{
atomic_t cl_destroy_in_flight;
wait_queue_head_t cl_destroy_waitq;
- struct mdc_rpc_lock *cl_rpc_lock;
-
/* modify rpcs in flight
* currently used for metadata only */
spinlock_t cl_mod_rpcs_lock;
#define OBD_FAIL_MDC_ENQUEUE_PAUSE 0x801
#define OBD_FAIL_MDC_OLD_EXT_FLAGS 0x802
#define OBD_FAIL_MDC_GETATTR_ENQUEUE 0x803
-#define OBD_FAIL_MDC_RPCS_SEM 0x804
+#define OBD_FAIL_MDC_RPCS_SEM 0x804 /* deprecated */
#define OBD_FAIL_MDC_LIGHTWEIGHT 0x805
#define OBD_FAIL_MDC_CLOSE 0x806
#define OBD_FAIL_MDC_MERGE 0x807
#define OBD_FAIL_OSP_CHECK_INVALID_REC 0x2100
#define OBD_FAIL_OSP_CHECK_ENOMEM 0x2101
#define OBD_FAIL_OSP_FAKE_PRECREATE 0x2102
+#define OBD_FAIL_OSP_RPCS_SEM 0x2104
/* barrier */
#define OBD_FAIL_MGS_BARRIER_READ_NET 0x2200
strcat(osdname, "-osd");
CDEBUG(D_HA, "%s: connect to %s (%s)\n", obd->obd_name, osdname, src);
- if (osp->opd_connect_mdt) {
- struct client_obd *cli = &osp->opd_obd->u.cli;
-
- OBD_ALLOC(cli->cl_rpc_lock, sizeof(*cli->cl_rpc_lock));
- if (!cli->cl_rpc_lock)
- GOTO(out_fini, rc = -ENOMEM);
- osp_init_rpc_lock(cli->cl_rpc_lock);
- }
+ osp_init_rpc_lock(osp);
osp->opd_dt_dev.dd_lu_dev.ld_ops = &osp_lu_ops;
osp->opd_dt_dev.dd_ops = &osp_dt_ops;
out_ref:
ptlrpcd_decref();
out_disconnect:
- if (osp->opd_connect_mdt) {
- struct client_obd *cli = &osp->opd_obd->u.cli;
- if (cli->cl_rpc_lock != NULL) {
- OBD_FREE_PTR(cli->cl_rpc_lock);
- cli->cl_rpc_lock = NULL;
- }
- }
obd_disconnect(osp->opd_storage_exp);
out_fini:
if (osdname)
LASSERT(osp->opd_obd);
osp_tunables_fini(osp);
- if (osp->opd_connect_mdt) {
- struct client_obd *cli = &osp->opd_obd->u.cli;
- if (cli->cl_rpc_lock != NULL) {
- OBD_FREE_PTR(cli->cl_rpc_lock);
- cli->cl_rpc_lock = NULL;
- }
- }
-
rc = client_obd_cleanup(osp->opd_obd);
if (rc != 0) {
ptlrpcd_decref();
#include <lustre_fid.h>
#include <lustre_update.h>
#include <lu_target.h>
-#include <lustre_mdc.h>
/*
* Infrastructure to support tracking of last committed llog record
__u64 ou_generation;
};
+struct osp_rpc_lock {
+ /** Lock protecting in-flight RPC concurrency. */
+ struct mutex rpcl_mutex;
+ /** Used for MDS/RPC load testing purposes. */
+ unsigned int rpcl_fakes;
+};
+
struct osp_device {
struct dt_device opd_dt_dev;
/* corresponded OST index */
struct lu_fid opd_gap_start_fid;
int opd_gap_count;
/* connection to OST */
+ struct osp_rpc_lock opd_rpc_lock;
struct obd_device *opd_obd;
struct obd_export *opd_exp;
struct obd_uuid opd_cluuid;
return osp->opd_dt_dev.dd_lu_dev.ld_site->ld_seq_site;
}
-#define osp_init_rpc_lock(lck) mdc_init_rpc_lock(lck)
+/**
+ * Serializes in-flight MDT-modifying RPC requests to preserve idempotency.
+ *
+ * This mutex is used to implement execute-once semantics on the MDT.
+ * The MDT stores the last transaction ID and result for every client in
+ * its last_rcvd file. If the client doesn't get a reply, it can safely
+ * resend the request and the MDT will reconstruct the reply being aware
+ * that the request has already been executed. Without this lock,
+ * execution status of concurrent in-flight requests would be
+ * overwritten.
+ *
+ * This imlpementation limits the extent to which we can keep a full pipeline
+ * of in-flight requests from a single client. This limitation can be
+ * overcome by allowing multiple slots per client in the last_rcvd file,
+ * see LU-6864.
+ */
+#define OSP_FAKE_RPCL_IT ((void *)0x2c0012bfUL)
+
+static inline void osp_init_rpc_lock(struct osp_device *osp)
+{
+ struct osp_rpc_lock *lck = &osp->opd_rpc_lock;
+
+ mutex_init(&lck->rpcl_mutex);
+ lck->rpcl_fakes = 0;
+}
static inline void osp_get_rpc_lock(struct osp_device *osp)
{
- struct mdc_rpc_lock *rpc_lock = osp->opd_obd->u.cli.cl_rpc_lock;
+ struct osp_rpc_lock *lck = &osp->opd_rpc_lock;
+
+ /* This would normally block until the existing request finishes.
+ * If fail_loc is set it will block until the regular request is
+ * done, then increment rpcl_fakes. Once that is non-zero it
+ * will only be cleared when all fake requests are finished.
+ * Only when all fake requests are finished can normal requests
+ * be sent, to ensure they are recoverable again.
+ */
+ again:
+ mutex_lock(&lck->rpcl_mutex);
+
+ if (CFS_FAIL_CHECK_QUIET(OBD_FAIL_MDC_RPCS_SEM) ||
+ CFS_FAIL_CHECK_QUIET(OBD_FAIL_OSP_RPCS_SEM)) {
+ lck->rpcl_fakes++;
+ mutex_unlock(&lck->rpcl_mutex);
+
+ return;
+ }
+
+ /* This will only happen when the CFS_FAIL_CHECK() was just turned
+ * off but there are still requests in progress. Wait until they
+ * finish. It doesn't need to be efficient in this extremely rare
+ * case, just have low overhead in the common case when it isn't true.
+ */
+ if (unlikely(lck->rpcl_fakes)) {
+ mutex_unlock(&lck->rpcl_mutex);
+ schedule_timeout(cfs_time_seconds(1) / 4);
- mdc_get_rpc_lock(rpc_lock, NULL);
+ goto again;
+ }
}
static inline void osp_put_rpc_lock(struct osp_device *osp)
{
- struct mdc_rpc_lock *rpc_lock = osp->opd_obd->u.cli.cl_rpc_lock;
+ struct osp_rpc_lock *lck = &osp->opd_rpc_lock;
+
+ if (lck->rpcl_fakes) { /* OBD_FAIL_OSP_RPCS_SEM */
+ mutex_lock(&lck->rpcl_mutex);
+
+ if (lck->rpcl_fakes) /* check again under lock */
+ lck->rpcl_fakes--;
+ }
- mdc_put_rpc_lock(rpc_lock, NULL);
+ mutex_unlock(&lck->rpcl_mutex);
}
static inline int osp_fid_diff(const struct lu_fid *fid1,