#ifdef __KERNEL__
# include <linux/module.h>
-# include <linux/pagemap.h>
-# include <linux/miscdevice.h>
-# include <linux/init.h>
+# include <linux/lustre_intent.h>
#else
# include <liblustre.h>
#endif
-#include <lustre_acl.h>
+#include <obd.h>
#include <obd_class.h>
#include <lustre_dlm.h>
-/* fid_res_name_eq() */
-#include <lustre_fid.h>
-#include <lprocfs_status.h>
+#include <lustre_fid.h> /* fid_res_name_eq() */
+#include <lustre_mdc.h>
+#include <lustre_net.h>
+#include <lustre_req_layout.h>
#include "mdc_internal.h"
struct mdc_getattr_args {
struct ldlm_enqueue_info *ga_einfo;
};
-int it_disposition(struct lookup_intent *it, int flag)
-{
- return it->d.lustre.it_disposition & flag;
-}
-EXPORT_SYMBOL(it_disposition);
-
-void it_set_disposition(struct lookup_intent *it, int flag)
-{
- it->d.lustre.it_disposition |= flag;
-}
-EXPORT_SYMBOL(it_set_disposition);
-
-void it_clear_disposition(struct lookup_intent *it, int flag)
-{
- it->d.lustre.it_disposition &= ~flag;
-}
-EXPORT_SYMBOL(it_clear_disposition);
-
int it_open_error(int phase, struct lookup_intent *it)
{
if (it_disposition(it, DISP_OPEN_LEASE)) {
}
ldlm_mode_t mdc_lock_match(struct obd_export *exp, __u64 flags,
- const struct lu_fid *fid, ldlm_type_t type,
- ldlm_policy_data_t *policy, ldlm_mode_t mode,
- struct lustre_handle *lockh)
+ const struct lu_fid *fid, ldlm_type_t type,
+ ldlm_policy_data_t *policy, ldlm_mode_t mode,
+ struct lustre_handle *lockh)
{
- struct ldlm_res_id res_id;
- ldlm_mode_t rc;
- ENTRY;
+ struct ldlm_res_id res_id;
+ ldlm_mode_t rc;
+ ENTRY;
- fid_build_reg_res_name(fid, &res_id);
- rc = ldlm_lock_match(class_exp2obd(exp)->obd_namespace, flags,
- &res_id, type, policy, mode, lockh, 0);
- RETURN(rc);
+ fid_build_reg_res_name(fid, &res_id);
+ /* LU-4405: Clear bits not supported by server */
+ policy->l_inodebits.bits &= exp_connect_ibits(exp);
+ rc = ldlm_lock_match(class_exp2obd(exp)->obd_namespace, flags,
+ &res_id, type, policy, mode, lockh, 0);
+ RETURN(rc);
}
int mdc_cancel_unused(struct obd_export *exp,
}
}
-static struct ptlrpc_request *mdc_intent_open_pack(struct obd_export *exp,
- struct lookup_intent *it,
- struct md_op_data *op_data,
- void *lmm, int lmmsize,
- void *cb_data)
+static struct ptlrpc_request *
+mdc_intent_open_pack(struct obd_export *exp, struct lookup_intent *it,
+ struct md_op_data *op_data)
{
- struct ptlrpc_request *req;
- struct obd_device *obddev = class_exp2obd(exp);
- struct ldlm_intent *lit;
- CFS_LIST_HEAD(cancels);
- int count = 0;
- int mode;
- int rc;
+ struct ptlrpc_request *req;
+ struct obd_device *obddev = class_exp2obd(exp);
+ struct ldlm_intent *lit;
+ const void *lmm = op_data->op_data;
+ int lmmsize = op_data->op_data_size;
+ struct list_head cancels = LIST_HEAD_INIT(cancels);
+ int count = 0;
+ int mode;
+ int rc;
ENTRY;
it->it_create_mode = (it->it_create_mode & ~S_IFMT) | S_IFREG;
req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
op_data->op_namelen + 1);
- req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_CLIENT,
- max(lmmsize, obddev->u.cli.cl_default_mds_easize));
+ req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_CLIENT,
+ max(lmmsize, obddev->u.cli.cl_default_mds_easize));
- rc = ldlm_prep_enqueue_req(exp, req, &cancels, count);
- if (rc) {
- ptlrpc_request_free(req);
- return NULL;
- }
+ rc = ldlm_prep_enqueue_req(exp, req, &cancels, count);
+ if (rc < 0) {
+ ptlrpc_request_free(req);
+ RETURN(ERR_PTR(rc));
+ }
spin_lock(&req->rq_lock);
req->rq_replay = req->rq_import->imp_replayable;
mdc_open_pack(req, op_data, it->it_create_mode, 0, it->it_flags, lmm,
lmmsize);
+ req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER,
+ obddev->u.cli.cl_max_mds_easize);
+
/* for remote client, fetch remote perm for current user */
if (client_is_remote(exp))
req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
struct ptlrpc_request *req;
struct ldlm_intent *lit;
int rc, count = 0, maxdata;
- CFS_LIST_HEAD(cancels);
+ struct list_head cancels = LIST_HEAD_INIT(cancels);
ENTRY;
/* pack the intended request */
mdc_unlink_pack(req, op_data);
- req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER,
- obddev->u.cli.cl_max_mds_easize);
- req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
- obddev->u.cli.cl_max_mds_cookiesize);
- ptlrpc_request_set_replen(req);
- RETURN(req);
+ req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER,
+ obddev->u.cli.cl_default_mds_easize);
+ req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
+ obddev->u.cli.cl_default_mds_cookiesize);
+ ptlrpc_request_set_replen(req);
+ RETURN(req);
}
static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp,
struct lookup_intent *it,
struct md_op_data *op_data)
{
- struct ptlrpc_request *req;
- struct obd_device *obddev = class_exp2obd(exp);
- obd_valid valid = OBD_MD_FLGETATTR | OBD_MD_FLEASIZE |
- OBD_MD_FLMODEASIZE | OBD_MD_FLDIREA |
- OBD_MD_FLMDSCAPA | OBD_MD_MEA |
- (client_is_remote(exp) ?
- OBD_MD_FLRMTPERM : OBD_MD_FLACL);
- struct ldlm_intent *lit;
- int rc;
- ENTRY;
+ struct ptlrpc_request *req;
+ struct obd_device *obddev = class_exp2obd(exp);
+ obd_valid valid = OBD_MD_FLGETATTR | OBD_MD_FLEASIZE |
+ OBD_MD_FLMODEASIZE | OBD_MD_FLDIREA |
+ OBD_MD_FLMDSCAPA | OBD_MD_MEA |
+ (client_is_remote(exp) ?
+ OBD_MD_FLRMTPERM : OBD_MD_FLACL);
+ struct ldlm_intent *lit;
+ int rc;
+ int easize;
+ ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_LDLM_INTENT_GETATTR);
lit = req_capsule_client_get(&req->rq_pill, &RMF_LDLM_INTENT);
lit->opc = (__u64)it->it_op;
- /* pack the intended request */
- mdc_getattr_pack(req, valid, it->it_flags, op_data,
- obddev->u.cli.cl_max_mds_easize);
+ if (obddev->u.cli.cl_default_mds_easize > 0)
+ easize = obddev->u.cli.cl_default_mds_easize;
+ else
+ easize = obddev->u.cli.cl_max_mds_easize;
- req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER,
- obddev->u.cli.cl_max_mds_easize);
- if (client_is_remote(exp))
- req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
- sizeof(struct mdt_remote_perm));
- ptlrpc_request_set_replen(req);
- RETURN(req);
+ /* pack the intended request */
+ mdc_getattr_pack(req, valid, it->it_flags, op_data, easize);
+
+ req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, easize);
+ if (client_is_remote(exp))
+ req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
+ sizeof(struct mdt_remote_perm));
+ ptlrpc_request_set_replen(req);
+ RETURN(req);
}
static struct ptlrpc_request *mdc_intent_layout_pack(struct obd_export *exp,
layout->li_opc = LAYOUT_INTENT_ACCESS;
req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER,
- obd->u.cli.cl_max_mds_easize);
+ obd->u.cli.cl_default_mds_easize);
ptlrpc_request_set_replen(req);
RETURN(req);
}
* happens immediately after swabbing below, new reply
* is swabbed by that handler correctly.
*/
- mdc_set_open_replay_data(NULL, NULL, req);
+ mdc_set_open_replay_data(NULL, NULL, it);
}
if ((body->valid & (OBD_MD_FLDIREA | OBD_MD_FLEASIZE)) != 0) {
/* install lvb_data */
lock_res_and_lock(lock);
if (lock->l_lvb_data == NULL) {
+ lock->l_lvb_type = LVB_T_LAYOUT;
lock->l_lvb_data = lmm;
lock->l_lvb_len = lvb_len;
lmm = NULL;
/* We always reserve enough space in the reply packet for a stripe MD, because
* we don't know in advance the file type. */
-int mdc_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo,
- struct lookup_intent *it, struct md_op_data *op_data,
- struct lustre_handle *lockh, void *lmm, int lmmsize,
- struct ptlrpc_request **reqp, __u64 extra_lock_flags)
+int mdc_enqueue(struct obd_export *exp,
+ struct ldlm_enqueue_info *einfo,
+ const union ldlm_policy_data *policy,
+ struct lookup_intent *it, struct md_op_data *op_data,
+ struct lustre_handle *lockh, __u64 extra_lock_flags)
{
struct obd_device *obddev = class_exp2obd(exp);
struct ptlrpc_request *req = NULL;
{ .l_inodebits = { MDS_INODELOCK_LAYOUT } };
static const ldlm_policy_data_t getxattr_policy = {
.l_inodebits = { MDS_INODELOCK_XATTR } };
- ldlm_policy_data_t const *policy = &lookup_policy;
int generation, resends = 0;
struct ldlm_reply *lockrep;
enum lvb_type lvb_type = 0;
LASSERTF(!it || einfo->ei_type == LDLM_IBITS, "lock type %d\n",
einfo->ei_type);
-
fid_build_reg_res_name(&op_data->op_fid1, &res_id);
- if (it) {
+ if (it != NULL) {
+ LASSERT(policy == NULL);
+
saved_flags |= LDLM_FL_HAS_INTENT;
- if (it->it_op & (IT_UNLINK | IT_GETATTR | IT_READDIR))
+ if (it->it_op & (IT_OPEN | IT_UNLINK | IT_GETATTR | IT_READDIR))
policy = &update_policy;
else if (it->it_op & IT_LAYOUT)
policy = &layout_policy;
else if (it->it_op & (IT_GETXATTR | IT_SETXATTR))
policy = &getxattr_policy;
+ else
+ policy = &lookup_policy;
}
- LASSERT(reqp == NULL);
-
generation = obddev->u.cli.cl_import->imp_generation;
resend:
flags = saved_flags;
- if (!it) {
- /* The only way right now is FLOCK, in this case we hide flock
- policy as lmm, but lmmsize is 0 */
- LASSERT(lmm && lmmsize == 0);
- LASSERTF(einfo->ei_type == LDLM_FLOCK, "lock type %d\n",
- einfo->ei_type);
- policy = (ldlm_policy_data_t *)lmm;
- res_id.name[3] = LDLM_FLOCK;
- } else if (it->it_op & IT_OPEN) {
- req = mdc_intent_open_pack(exp, it, op_data, lmm, lmmsize,
- einfo->ei_cbdata);
- policy = &update_policy;
- einfo->ei_cbdata = NULL;
- lmm = NULL;
+ if (it == NULL) {
+ /* The only way right now is FLOCK. */
+ LASSERTF(einfo->ei_type == LDLM_FLOCK, "lock type %d\n",
+ einfo->ei_type);
+ res_id.name[3] = LDLM_FLOCK;
+ } else if (it->it_op & IT_OPEN) {
+ req = mdc_intent_open_pack(exp, it, op_data);
} else if (it->it_op & IT_UNLINK) {
req = mdc_intent_unlink_pack(exp, it, op_data);
} else if (it->it_op & (IT_GETATTR | IT_LOOKUP)) {
* rpcs in flight counter. We do not do flock request limiting, though*/
if (it) {
mdc_get_rpc_lock(obddev->u.cli.cl_rpc_lock, it);
- rc = mdc_enter_request(&obddev->u.cli);
+ rc = obd_get_request_slot(&obddev->u.cli);
if (rc != 0) {
mdc_put_rpc_lock(obddev->u.cli.cl_rpc_lock, it);
mdc_clear_replay_flag(req, 0);
(einfo->ei_type == LDLM_FLOCK) &&
(einfo->ei_mode == LCK_NL))
goto resend;
- RETURN(rc);
- }
+ RETURN(rc);
+ }
- mdc_exit_request(&obddev->u.cli);
- mdc_put_rpc_lock(obddev->u.cli.cl_rpc_lock, it);
+ obd_put_request_slot(&obddev->u.cli);
+ mdc_put_rpc_lock(obddev->u.cli.cl_rpc_lock, it);
- if (rc < 0) {
- CERROR("ldlm_cli_enqueue: %d\n", rc);
- mdc_clear_replay_flag(req, rc);
- ptlrpc_req_finished(req);
- RETURN(rc);
- }
+ if (rc < 0) {
+ CDEBUG_LIMIT((rc == -EACCES || rc == -EIDRM) ? D_INFO : D_ERROR,
+ "%s: ldlm_cli_enqueue failed: rc = %d\n",
+ obddev->obd_name, rc);
- lockrep = req_capsule_server_get(&req->rq_pill, &RMF_DLM_REP);
- LASSERT(lockrep != NULL);
+ mdc_clear_replay_flag(req, rc);
+ ptlrpc_req_finished(req);
+ RETURN(rc);
+ }
+
+ lockrep = req_capsule_server_get(&req->rq_pill, &RMF_DLM_REP);
+ LASSERT(lockrep != NULL);
lockrep->lock_policy_res2 =
ptlrpc_status_ntoh(lockrep->lock_policy_res2);
LASSERT(request != LP_POISON);
LASSERT(request->rq_repmsg != LP_POISON);
+ if (it->it_op & IT_READDIR)
+ RETURN(0);
+
if (!it_disposition(it, DISP_IT_EXECD)) {
/* The server failed before it even started executing the
* intent, i.e. because it couldn't unpack the request. */
if (fid_is_sane(&op_data->op_fid2) &&
it->it_create_mode & M_CHECK_STALE &&
it->it_op != IT_GETATTR) {
- it_set_disposition(it, DISP_ENQ_COMPLETE);
-
/* Also: did we find the same inode? */
/* sever can return one of two fids:
* op_fid2 - new allocated fid - if file is created.
} else {
fid_build_reg_res_name(fid, &res_id);
switch (it->it_op) {
- case IT_GETATTR:
- policy.l_inodebits.bits = MDS_INODELOCK_UPDATE;
- break;
+ case IT_GETATTR:
+ /* File attributes are held under multiple bits:
+ * nlink is under lookup lock, size and times are
+ * under UPDATE lock and recently we've also got
+ * a separate permissions lock for owner/group/acl that
+ * were protected by lookup lock before.
+ * Getattr must provide all of that information,
+ * so we need to ensure we have all of those locks.
+ * Unfortunately, if the bits are split across multiple
+ * locks, there's no easy way to match all of them here,
+ * so an extra RPC would be performed to fetch all
+ * of those bits at once for now. */
+ /* For new MDTs(> 2.4), UPDATE|PERM should be enough,
+ * but for old MDTs (< 2.4), permission is covered
+ * by LOOKUP lock, so it needs to match all bits here.*/
+ policy.l_inodebits.bits = MDS_INODELOCK_UPDATE |
+ MDS_INODELOCK_LOOKUP |
+ MDS_INODELOCK_PERM;
+ break;
+ case IT_READDIR:
+ policy.l_inodebits.bits = MDS_INODELOCK_UPDATE;
+ break;
case IT_LAYOUT:
policy.l_inodebits.bits = MDS_INODELOCK_LAYOUT;
break;
policy.l_inodebits.bits = MDS_INODELOCK_LOOKUP;
break;
}
- mode = ldlm_lock_match(exp->exp_obd->obd_namespace,
- LDLM_FL_BLOCK_GRANTED, &res_id,
- LDLM_IBITS, &policy,
- LCK_CR|LCK_CW|LCK_PR|LCK_PW, &lockh, 0);
+
+ mode = mdc_lock_match(exp, LDLM_FL_BLOCK_GRANTED, fid,
+ LDLM_IBITS, &policy,
+ LCK_CR | LCK_CW | LCK_PR | LCK_PW,
+ &lockh);
}
if (mode) {
* child lookup.
*/
int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
- void *lmm, int lmmsize, struct lookup_intent *it,
- int lookup_flags, struct ptlrpc_request **reqp,
- ldlm_blocking_callback cb_blocking,
- __u64 extra_lock_flags)
+ struct lookup_intent *it, struct ptlrpc_request **reqp,
+ ldlm_blocking_callback cb_blocking, __u64 extra_lock_flags)
{
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_IBITS,
+ .ei_mode = it_to_lock_mode(it),
+ .ei_cb_bl = cb_blocking,
+ .ei_cb_cp = ldlm_completion_ast,
+ };
struct lustre_handle lockh;
int rc = 0;
ENTRY;
LASSERT(it);
CDEBUG(D_DLMTRACE, "(name: %.*s,"DFID") in obj "DFID
- ", intent: %s flags %#Lo\n", op_data->op_namelen,
+ ", intent: %s flags %#"LPF64"o\n", op_data->op_namelen,
op_data->op_name, PFID(&op_data->op_fid2),
PFID(&op_data->op_fid1), ldlm_it2str(it->it_op),
it->it_flags);
- lockh.cookie = 0;
- if (fid_is_sane(&op_data->op_fid2) &&
- (it->it_op & (IT_LOOKUP | IT_GETATTR))) {
- /* We could just return 1 immediately, but since we should only
- * be called in revalidate_it if we already have a lock, let's
- * verify that. */
- it->d.lustre.it_lock_handle = 0;
- rc = mdc_revalidate_lock(exp, it, &op_data->op_fid2, NULL);
- /* Only return failure if it was not GETATTR by cfid
- (from inode_revalidate) */
- if (rc || op_data->op_namelen != 0)
- RETURN(rc);
- }
+ lockh.cookie = 0;
+ if (fid_is_sane(&op_data->op_fid2) &&
+ (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_READDIR))) {
+ /* We could just return 1 immediately, but since we should only
+ * be called in revalidate_it if we already have a lock, let's
+ * verify that. */
+ it->d.lustre.it_lock_handle = 0;
+ rc = mdc_revalidate_lock(exp, it, &op_data->op_fid2, NULL);
+ /* Only return failure if it was not GETATTR by cfid
+ (from inode_revalidate) */
+ if (rc || op_data->op_namelen != 0)
+ RETURN(rc);
+ }
- /* lookup_it may be called only after revalidate_it has run, because
- * revalidate_it cannot return errors, only zero. Returning zero causes
- * this call to lookup, which *can* return an error.
- *
- * We only want to execute the request associated with the intent one
- * time, however, so don't send the request again. Instead, skip past
- * this and use the request from revalidate. In this case, revalidate
- * never dropped its reference, so the refcounts are all OK */
- if (!it_disposition(it, DISP_ENQ_COMPLETE)) {
- struct ldlm_enqueue_info einfo = {
- .ei_type = LDLM_IBITS,
- .ei_mode = it_to_lock_mode(it),
- .ei_cb_bl = cb_blocking,
- .ei_cb_cp = ldlm_completion_ast,
- };
-
- /* For case if upper layer did not alloc fid, do it now. */
- if (!fid_is_sane(&op_data->op_fid2) && it->it_op & IT_CREAT) {
- rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data);
- if (rc < 0) {
- CERROR("Can't alloc new fid, rc %d\n", rc);
- RETURN(rc);
- }
- }
- rc = mdc_enqueue(exp, &einfo, it, op_data, &lockh,
- lmm, lmmsize, NULL, extra_lock_flags);
- if (rc < 0)
- RETURN(rc);
- } else if (!fid_is_sane(&op_data->op_fid2) ||
- !(it->it_create_mode & M_CHECK_STALE)) {
- /* DISP_ENQ_COMPLETE set means there is extra reference on
- * request referenced from this intent, saved for subsequent
- * lookup. This path is executed when we proceed to this
- * lookup, so we clear DISP_ENQ_COMPLETE */
- it_clear_disposition(it, DISP_ENQ_COMPLETE);
- }
- *reqp = it->d.lustre.it_data;
+ /* For case if upper layer did not alloc fid, do it now. */
+ if (!fid_is_sane(&op_data->op_fid2) && it->it_op & IT_CREAT) {
+ rc = mdc_fid_alloc(NULL, exp, &op_data->op_fid2, op_data);
+ if (rc < 0) {
+ CERROR("Can't alloc new fid, rc %d\n", rc);
+ RETURN(rc);
+ }
+ }
+
+ rc = mdc_enqueue(exp, &einfo, NULL, it, op_data, &lockh,
+ extra_lock_flags);
+ if (rc < 0)
+ RETURN(rc);
+
+ *reqp = it->d.lustre.it_data;
rc = mdc_finish_intent_lock(exp, *reqp, op_data, it, &lockh);
RETURN(rc);
}
obddev = class_exp2obd(exp);
- mdc_exit_request(&obddev->u.cli);
+ obd_put_request_slot(&obddev->u.cli);
if (OBD_FAIL_CHECK(OBD_FAIL_MDC_GETATTR_ENQUEUE))
rc = -ETIMEDOUT;
__u64 flags = LDLM_FL_HAS_INTENT;
ENTRY;
- CDEBUG(D_DLMTRACE,"name: %.*s in inode "DFID", intent: %s flags %#Lo\n",
+ CDEBUG(D_DLMTRACE, "name: %.*s in inode "DFID", intent: %s flags %#"
+ LPF64"o\n",
op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1),
ldlm_it2str(it->it_op), it->it_flags);
- fid_build_reg_res_name(&op_data->op_fid1, &res_id);
- req = mdc_intent_getattr_pack(exp, it, op_data);
- if (!req)
- RETURN(-ENOMEM);
+ fid_build_reg_res_name(&op_data->op_fid1, &res_id);
+ req = mdc_intent_getattr_pack(exp, it, op_data);
+ if (IS_ERR(req))
+ RETURN(PTR_ERR(req));
- rc = mdc_enter_request(&obddev->u.cli);
+ rc = obd_get_request_slot(&obddev->u.cli);
if (rc != 0) {
ptlrpc_req_finished(req);
RETURN(rc);
rc = ldlm_cli_enqueue(exp, &req, einfo, &res_id, &policy, &flags, NULL,
0, LVB_T_NONE, &minfo->mi_lockh, 1);
if (rc < 0) {
- mdc_exit_request(&obddev->u.cli);
+ obd_put_request_slot(&obddev->u.cli);
ptlrpc_req_finished(req);
RETURN(rc);
}