OBD_CONNECT_IBITS |
OBD_CONNECT_MDS_MDS |
OBD_CONNECT_FID;
- rc = obd_connect(env, conn, mdc, &mdc->obd_uuid, ocd);
+ rc = obd_connect(env, conn, mdc, &mdc->obd_uuid, ocd, NULL);
OBD_FREE_PTR(ocd);
if (rc) {
CERROR("target %s connect error %d\n",
#include <lustre_lib.h>
+/* #define LUSTRE_HASH_DEBUG 1 */
+
/* define the hash bucket*/
struct lustre_hash_bucket {
struct hlist_head lhb_head;
* it will help us to analyse the hash distribute
*/
int lhb_item_count;
-#endif
+#endif
};
struct lustre_hash_operations;
RETURN(0);
}
+typedef void (*hash_item_iterate_cb) (void *obj, void *data);
+
int lustre_hash_init(struct lustre_class_hash_body **hash_body,
char *hashname, __u32 hashsize,
struct lustre_hash_operations *hash_operations);
void lustre_hash_exit(struct lustre_class_hash_body **hash_body);
int lustre_hash_additem_unique(struct lustre_class_hash_body *hash_body,
void *key, struct hlist_node *actual_hnode);
+void *lustre_hash_findadd_unique(struct lustre_class_hash_body *hash_body,
+ void *key, struct hlist_node *actual_hnode);
int lustre_hash_additem(struct lustre_class_hash_body *hash_body, void *key,
struct hlist_node *actual_hnode);
int lustre_hash_delitem_by_key(struct lustre_class_hash_body *hash_body,
void *key);
int lustre_hash_delitem(struct lustre_class_hash_body *hash_body, void *key,
struct hlist_node *hash_item);
+void lustre_hash_bucket_iterate(struct lustre_class_hash_body *hash_body,
+ void *key, hash_item_iterate_cb,
+ void *data);
+void lustre_hash_iterate_all(struct lustre_class_hash_body *hash_body,
+ hash_item_iterate_cb, void *data);
+
void * lustre_hash_get_object_by_key(struct lustre_class_hash_body *hash_body,
void *key);
+__u32 djb2_hashfn(struct lustre_class_hash_body *hash_body, void* key,
+ size_t size);
+
/* ( uuid <-> export ) hash operations define */
__u32 uuid_hashfn(struct lustre_class_hash_body *hash_body, void * key);
int uuid_hash_key_compare(void *key, struct hlist_node * compared_hnode);
void * conn_refcount_get(struct hlist_node * actual_hnode);
void conn_refcount_put(struct hlist_node * actual_hnode);
+/* ( nid <-> nidstats ) hash operations define. uses nid_hashfn */
+int nidstats_hash_key_compare(void *key, struct hlist_node * compared_hnode);
+void* nidstats_refcount_get(struct hlist_node * actual_hnode);
+void nidstats_refcount_put(struct hlist_node * actual_hnode);
+extern struct lustre_hash_operations nid_stat_hash_operations;
+
#endif /* __CLASS_HASH_H */
const char *units);
extern void lprocfs_free_obd_stats(struct obd_device *obddev);
struct obd_export;
-extern int lprocfs_exp_setup(struct obd_export *exp);
+struct nid_stat;
+extern int lprocfs_add_clear_entry(struct obd_device * obd,
+ cfs_proc_dir_entry_t *entry);
+extern int lprocfs_exp_setup(struct obd_export *exp,
+ lnet_nid_t peer_nid, int *newnid);
extern int lprocfs_exp_cleanup(struct obd_export *exp);
+extern int lprocfs_add_simple(struct proc_dir_entry *root,
+ char *name, read_proc_t *read_proc,
+ write_proc_t *write_proc, void *data);
+extern void lprocfs_free_per_client_stats(struct obd_device *obd);
+extern int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
+ unsigned long count, void *data);
+extern int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+
extern int lprocfs_register_stats(cfs_proc_dir_entry_t *root, const char *name,
struct lprocfs_stats *stats);
extern int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list);
extern int lprocfs_obd_cleanup(struct obd_device *obd);
+extern int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
+ read_proc_t *read_proc, write_proc_t *write_proc,
+ void *data);
+extern void lprocfs_free_per_client_stats(struct obd_device *obd);
extern struct file_operations lprocfs_evict_client_fops;
extern int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name,
{ return; }
struct obd_export;
+static inline int lprocfs_add_clear_entry(struct obd_export *exp)
+{ return 0; }
static inline int lprocfs_exp_setup(struct obd_export *exp)
{ return 0; }
static inline int lprocfs_exp_cleanup(struct obd_export *exp)
{ return 0; }
+static inline int lprocfs_add_simple(struct proc_dir_entry *root,
+ char *name,
+ read_proc_t *read_proc,
+ write_proc_t *write_proc,
+ void *data)
+{return 0; }
+static inline void lprocfs_free_per_client_stats(struct obd_device *obd)
+{}
+static inline
+int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{return count;}
+static inline
+int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{return count;}
static inline cfs_proc_dir_entry_t *
lprocfs_register(const char *name, cfs_proc_dir_entry_t *parent,
struct brw_stats fed_brw_stats;
};
+typedef struct nid_stat {
+ lnet_nid_t nid;
+ struct hlist_node nid_hash;
+ struct list_head nid_list;
+ struct obd_device *nid_obd;
+ struct proc_dir_entry *nid_proc;
+ struct lprocfs_stats *nid_stats;
+ struct brw_stats *nid_brw_stats;
+ int nid_exp_ref_count;
+}nid_stat_t;
+
struct obd_export {
struct portals_handle exp_handle;
atomic_t exp_refcount;
struct list_head exp_obd_chain_timed;
struct obd_device *exp_obd;
struct obd_import *exp_imp_reverse; /* to make RPCs backwards */
- struct proc_dir_entry *exp_proc;
- struct lprocfs_stats *exp_ops_stats;
+ struct nid_stat *exp_nid_stats;
struct lprocfs_stats *exp_md_stats;
struct lprocfs_stats *exp_ldlm_stats;
struct ptlrpc_connection *exp_connection;
int client_obd_cleanup(struct obd_device *obddev);
int client_connect_import(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *obd,
- struct obd_uuid *cluuid, struct obd_connect_data *);
+ struct obd_uuid *cluuid, struct obd_connect_data *,
+ void *localdata);
int client_disconnect_export(struct obd_export *exp);
int client_import_add_conn(struct obd_import *imp, struct obd_uuid *uuid,
int priority);
/* uuid-export hash body */
struct lustre_class_hash_body *obd_uuid_hash_body;
/* nid-export hash body */
- struct lustre_class_hash_body *obd_nid_hash_body;
- atomic_t obd_refcount;
+ struct lustre_class_hash_body *obd_nid_hash_body;
+ /* nid stats body */
+ struct lustre_class_hash_body *obd_nid_stats_hash_body;
+ struct list_head obd_nid_stats;
+ atomic_t obd_refcount;
cfs_waitq_t obd_refcount_waitq;
struct list_head obd_exports;
int obd_num_exports;
+ spinlock_t obd_nid_lock;
struct ldlm_namespace *obd_namespace;
struct ptlrpc_client obd_ldlm_client; /* XXX OST/MDS only */
/* a spinlock is OK for what we do now, may need a semaphore later */
struct lprocfs_stats *md_stats;
cfs_proc_dir_entry_t *obd_proc_entry;
- cfs_proc_dir_entry_t *obd_proc_exports;
+ cfs_proc_dir_entry_t *obd_proc_exports_entry;
cfs_proc_dir_entry_t *obd_svc_procroot;
struct lprocfs_stats *obd_svc_stats;
- struct semaphore obd_proc_exp_sem;
atomic_t obd_evict_inprogress;
cfs_waitq_t obd_evict_inprogress_waitq;
};
* asked for. If @ocd == NULL, use default parameters. */
int (*o_connect)(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *src,
- struct obd_uuid *cluuid, struct obd_connect_data *ocd);
+ struct obd_uuid *cluuid, struct obd_connect_data *ocd,
+ void *localdata);
int (*o_reconnect)(const struct lu_env *env,
struct obd_export *exp, struct obd_device *src,
struct obd_uuid *cluuid,
OBD_COUNTER_OFFSET(op); \
LASSERT(coffset < (export)->exp_obd->obd_stats->ls_num); \
lprocfs_counter_incr((export)->exp_obd->obd_stats, coffset); \
- if ((export)->exp_ops_stats != NULL) \
+ if ((export)->exp_nid_stats != NULL && \
+ (export)->exp_nid_stats->nid_stats != NULL) \
lprocfs_counter_incr( \
- (export)->exp_ops_stats, coffset); \
+ (export)->exp_nid_stats->nid_stats, coffset);\
}
#define MD_COUNTER_OFFSET(op) \
static inline int obd_connect(const struct lu_env *env,
struct lustre_handle *conn,struct obd_device *obd,
struct obd_uuid *cluuid,
- struct obd_connect_data *d)
+ struct obd_connect_data *d,
+ void *localdata)
{
int rc;
#ifdef LIBCFS_DEBUG
OBD_CHECK_DT_OP(obd, connect, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, connect);
- rc = OBP(obd, connect)(env, conn, obd, cluuid, d);
+ rc = OBP(obd, connect)(env, conn, obd, cluuid, d, localdata);
/* check that only subset is granted */
LASSERT(ergo(d != NULL,
(d->ocd_connect_flags & ocf) == d->ocd_connect_flags));
int client_connect_import(const struct lu_env *env,
struct lustre_handle *dlm_handle,
struct obd_device *obd, struct obd_uuid *cluuid,
- struct obd_connect_data *data)
+ struct obd_connect_data *data, void *localdata)
{
struct client_obd *cli = &obd->u.cli;
struct obd_import *imp = cli->cl_import;
int rc = 0;
int initial_conn = 0;
struct obd_connect_data *data, *tmpdata;
+ lnet_nid_t client_nid = 0;
ENTRY;
OBD_RACE(OBD_FAIL_TGT_CONN_RACE);
/* Tell the client if we support replayable requests */
if (target->obd_replayable)
lustre_msg_add_op_flags(req->rq_repmsg, MSG_CONNECT_REPLAYABLE);
+ client_nid = req->rq_peer.nid;
if (export == NULL) {
if (target->obd_recovering) {
} else {
dont_check_exports:
rc = obd_connect(req->rq_svc_thread->t_env,
- &conn, target, &cluuid, data);
+ &conn, target, &cluuid, data,
+ &client_nid);
}
} else {
rc = obd_reconnect(req->rq_svc_thread->t_env,
#endif
ocd->ocd_version = LUSTRE_VERSION_CODE;
- rc = obd_connect(NULL, &mgc_conn, obd, &mgc_uuid, ocd);
+ rc = obd_connect(NULL, &mgc_conn, obd, &mgc_uuid, ocd, NULL);
if (rc) {
CERROR("cannot connect to %s at %s: rc = %d\n",
LUSTRE_MGS_OBDNAME, mgsnid, rc);
ocd.ocd_version = LUSTRE_VERSION_CODE;
/* setup mdc */
- err = obd_connect(NULL, &md_conn, obd, &sbi->ll_sb_uuid, &ocd);
+ err = obd_connect(NULL, &md_conn, obd, &sbi->ll_sb_uuid, &ocd, NULL);
if (err) {
CERROR("cannot connect to %s: rc = %d\n", mdc, err);
GOTO(out_free, err);
OBD_CONNECT_VERSION | OBD_CONNECT_TRUNCLOCK |
OBD_CONNECT_FID;
ocd.ocd_version = LUSTRE_VERSION_CODE;
- err = obd_connect(NULL, &dt_conn, obd, &sbi->ll_sb_uuid, &ocd);
+ err = obd_connect(NULL, &dt_conn, obd, &sbi->ll_sb_uuid, &ocd, NULL);
if (err) {
CERROR("cannot connect to %s: rc = %d\n", osc, err);
GOTO(out_md, err);
data->ocd_connect_flags |= OBD_CONNECT_LCL_CLIENT;
}
- err = obd_connect(NULL, &md_conn, obd, &sbi->ll_sb_uuid, data);
+ err = obd_connect(NULL, &md_conn, obd, &sbi->ll_sb_uuid, data, NULL);
if (err == -EBUSY) {
LCONSOLE_ERROR_MSG(0x14f, "An MDT (md %s) is performing "
"recovery, of which this client is not a "
obd->obd_upcall.onu_upcall = ll_ocd_update;
data->ocd_brw_size = PTLRPC_MAX_BRW_PAGES << CFS_PAGE_SHIFT;
- err = obd_connect(NULL, &dt_conn, obd, &sbi->ll_sb_uuid, data);
+ err = obd_connect(NULL, &dt_conn, obd, &sbi->ll_sb_uuid, data, NULL);
if (err == -EBUSY) {
LCONSOLE_ERROR_MSG(0x150, "An OST (dt %s) is performing "
"recovery, of which this client is not a "
* caller that everything is okay. Real connection will be performed later. */
static int lmv_connect(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *obd,
- struct obd_uuid *cluuid, struct obd_connect_data *data)
+ struct obd_uuid *cluuid, struct obd_connect_data *data,
+ void *localdata)
{
#ifdef __KERNEL__
struct proc_dir_entry *lmv_proc_dir;
}
rc = obd_connect(NULL, &conn, mdc_obd, &lmv_mdc_uuid,
- &lmv->conn_data);
+ &lmv->conn_data, NULL);
if (rc) {
CERROR("target %s connect error %d\n", tgt->ltd_uuid.uuid, rc);
RETURN(rc);
RETURN(0);
}
- rc = obd_connect(NULL, &conn, tgt_obd, &lov_osc_uuid, data);
+ rc = obd_connect(NULL, &conn, tgt_obd, &lov_osc_uuid, data, NULL);
if (rc) {
CERROR("Target %s connect error %d\n",
obd_uuid2str(&tgt_uuid), rc);
static int lov_connect(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *obd,
- struct obd_uuid *cluuid, struct obd_connect_data *data)
+ struct obd_uuid *cluuid, struct obd_connect_data *data,
+ void *localdata)
{
struct lov_obd *lov = &obd->u.lov;
struct lov_tgt_desc *tgt;
static int mdc_connect(const struct lu_env *env,
struct lustre_handle *dlm_handle,
struct obd_device *obd, struct obd_uuid *cluuid,
- struct obd_connect_data *data)
+ struct obd_connect_data *data,
+ void *localdata)
{
struct obd_import *imp = obd->u.cli.cl_import;
obd->obd_name);
}
- return client_connect_import(env, dlm_handle, obd, cluuid, data);
+ return client_connect_import(env, dlm_handle, obd, cluuid, data, NULL);
}
struct obd_ops mdc_obd_ops = {
*/
static int mds_connect(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *obd,
- struct obd_uuid *cluuid, struct obd_connect_data *data)
+ struct obd_uuid *cluuid, struct obd_connect_data *data,
+ void *localdata)
{
struct obd_export *exp;
struct mds_export_data *med;
struct mds_client_data *mcd = NULL;
+ lnet_nid_t *client_nid = (lnet_nid_t *)localdata;
int rc;
ENTRY;
memcpy(mcd->mcd_uuid, cluuid, sizeof(mcd->mcd_uuid));
med->med_mcd = mcd;
- rc = mds_client_add(obd, exp, -1);
+ rc = mds_client_add(obd, exp, -1, *client_nid);
GOTO(out, rc);
out:
lprocfs_alloc_obd_stats(obd, LPROC_MDS_LAST) == 0) {
/* Init private stats here */
mds_stats_counter_init(obd->obd_stats);
- obd->obd_proc_exports = proc_mkdir("exports",
- obd->obd_proc_entry);
+ obd->obd_proc_exports_entry = proc_mkdir("exports",
+ obd->obd_proc_entry);
}
rc = mds_fs_setup(obd, mnt);
GOTO(err_ns, rc);
}
+ if (obd->obd_proc_exports_entry)
+ lprocfs_add_simple(obd->obd_proc_exports_entry,
+ "clear", lprocfs_nid_stats_clear_read,
+ lprocfs_nid_stats_clear_write, obd);
+
rc = mds_lov_presetup(mds, lcfg);
if (rc < 0)
GOTO(err_fs, rc);
mds->mds_group_hash = NULL;
#endif
err_ns:
- lprocfs_obd_cleanup(obd);
lprocfs_free_obd_stats(obd);
+ lprocfs_obd_cleanup(obd);
ldlm_namespace_free(obd->obd_namespace, 0);
obd->obd_namespace = NULL;
err_ops:
we just need to drop our ref */
class_export_put(mds->mds_osc_exp);
- lprocfs_obd_cleanup(obd);
+ remove_proc_entry("clear", obd->obd_proc_exports_entry);
+ lprocfs_free_per_client_stats(obd);
lprocfs_free_obd_stats(obd);
+ lprocfs_obd_cleanup(obd);
lquota_cleanup(mds_quota_interface_ref, obd);
void mds_counter_incr(struct obd_export *exp, int opcode)
{
- lprocfs_counter_incr(exp->exp_obd->obd_stats, opcode);
- lprocfs_counter_incr(exp->exp_ops_stats, opcode);
+ if (exp->exp_obd && exp->exp_obd->obd_stats)
+ lprocfs_counter_incr(exp->exp_obd->obd_stats, opcode);
+ if (exp->exp_nid_stats && exp->exp_nid_stats->nid_stats != NULL)
+ lprocfs_counter_incr(exp->exp_nid_stats->nid_stats, opcode);
+
}
void mds_stats_counter_init(struct lprocfs_stats *stats)
#include "mds_internal.h"
-static int mds_export_stats_init(struct obd_device *obd, struct obd_export *exp)
+static int mds_export_stats_init(struct obd_device *obd,
+ struct obd_export *exp,
+ lnet_nid_t client_nid)
{
- int rc, num_stats;
-
- rc = lprocfs_exp_setup(exp);
+ int rc, num_stats, newnid;
+ rc = lprocfs_exp_setup(exp, client_nid, &newnid);
if (rc)
return rc;
- num_stats = (sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
- LPROC_MDS_LAST - 1;
- exp->exp_ops_stats = lprocfs_alloc_stats(num_stats,
- LPROCFS_STATS_FLAG_NOPERCPU);
- if (exp->exp_ops_stats == NULL)
- return -ENOMEM;
- lprocfs_init_ops_stats(LPROC_MDS_LAST, exp->exp_ops_stats);
- mds_stats_counter_init(exp->exp_ops_stats);
- lprocfs_register_stats(exp->exp_proc, "stats", exp->exp_ops_stats);
+
+ if (client_nid && newnid) {
+ struct nid_stat *tmp = exp->exp_nid_stats;
+ LASSERT(tmp != NULL);
+ num_stats = (sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
+ LPROC_MDS_LAST - 1;
+ tmp->nid_stats = lprocfs_alloc_stats(num_stats,
+ LPROCFS_STATS_FLAG_NOPERCPU);
+ if (tmp->nid_stats == NULL)
+ return -ENOMEM;
+
+ lprocfs_init_ops_stats(LPROC_MDS_LAST, tmp->nid_stats);
+ rc = lprocfs_register_stats(tmp->nid_proc, "stats",
+ tmp->nid_stats);
+ if (rc)
+ return rc;
+ mds_stats_counter_init(tmp->nid_stats);
+ }
return 0;
}
* mds_init_server_data() callsite needs to be fixed.
*/
int mds_client_add(struct obd_device *obd, struct obd_export *exp,
- int cl_idx)
+ int cl_idx, lnet_nid_t client_nid)
{
struct mds_obd *mds = &obd->u.mds;
struct mds_export_data *med = &exp->exp_mds_data;
med->med_lr_off = le32_to_cpu(mds->mds_server_data->lsd_client_start) +
(cl_idx * le16_to_cpu(mds->mds_server_data->lsd_client_size));
LASSERTF(med->med_lr_off > 0, "med_lr_off = %llu\n", med->med_lr_off);
- mds_export_stats_init(obd, exp);
+ mds_export_stats_init(obd, exp, client_nid);
if (new_client) {
struct lvfs_run_ctxt saved;
} else {
med = &exp->exp_mds_data;
med->med_mcd = mcd;
- rc = mds_client_add(obd, exp, cl_idx);
+ rc = mds_client_add(obd, exp, cl_idx, 0);
LASSERTF(rc == 0, "rc = %d\n", rc); /* can't fail existing */
mcd = NULL;
goto err_pop;
}
-
int mds_fs_cleanup(struct obd_device *obd)
{
struct mds_obd *mds = &obd->u.mds;
struct dentry *dchild, struct lustre_handle *lockh);
/* mds/mds_fs.c */
-int mds_client_add(struct obd_device *obd, struct obd_export *exp, int cl_off);
+int mds_client_add(struct obd_device *obd, struct obd_export *exp,
+ int cl_off, lnet_nid_t client_nid);
int mds_client_free(struct obd_export *exp);
int mds_obd_create(struct obd_export *exp, struct obdo *oa,
struct lov_stripe_md **ea, struct obd_trans_info *oti);
data->ocd_version = LUSTRE_VERSION_CODE;
data->ocd_group = mds->mds_id + FILTER_GROUP_MDS0;
/* NB: lov_connect() needs to fill in .ocd_index for each OST */
- rc = obd_connect(NULL, &conn, mds->mds_osc_obd, &obd->obd_uuid, data);
+ rc = obd_connect(NULL, &conn, mds->mds_osc_obd, &obd->obd_uuid, data, NULL);
OBD_FREE(data, sizeof(*data));
if (rc) {
CERROR("MDS cannot connect to LOV %s (%d)\n", lov_name, rc);
static int mdt_obd_connect(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *obd,
struct obd_uuid *cluuid,
- struct obd_connect_data *data)
+ struct obd_connect_data *data,
+ void *localdata)
{
struct mdt_thread_info *info;
struct mdt_client_data *mcd;
rc = lprocfs_obd_seq_create(obd, "filesystems", 0444,
&mgs_fs_fops, obd);
mgs->mgs_proc_live = proc_mkdir("live", obd->obd_proc_entry);
- obd->obd_proc_exports = proc_mkdir("exports", obd->obd_proc_entry);
+ obd->obd_proc_exports_entry = proc_mkdir("exports", obd->obd_proc_entry);
return rc;
}
void mgs_counter_incr(struct obd_export *exp, int opcode)
{
lprocfs_counter_incr(exp->exp_obd->obd_stats, opcode);
- lprocfs_counter_incr(exp->exp_ops_stats, opcode);
+ if (exp->exp_nid_stats && exp->exp_nid_stats->nid_stats != NULL)
+ lprocfs_counter_incr(exp->exp_nid_stats->nid_stats, opcode);
}
void mgs_stats_counter_init(struct lprocfs_stats *stats)
/* Establish a connection to the MGS.*/
static int mgs_connect(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *obd,
- struct obd_uuid *cluuid, struct obd_connect_data *data)
+ struct obd_uuid *cluuid, struct obd_connect_data *data,
+ void *localdata)
{
struct obd_export *exp;
int rc;
n++;
i >>= 1;
}
-
+
LASSERTF(n == 1, "hashsize %u isn't 2^n\n", hashsize);
/* alloc space for hash_body */
/* alloc space for the hash tables */
OBD_ALLOC(hash_body->lchb_hash_tables,
- sizeof(*hash_body->lchb_hash_tables) * hash_body->lchb_hash_max_size);
+ sizeof(*hash_body->lchb_hash_tables) * hash_body->lchb_hash_max_size);
if (hash_body->lchb_hash_tables == NULL) {
OBD_FREE(hash_body, sizeof(*hash_body));
EXPORT_SYMBOL(lustre_hash_additem_unique);
/*
+ * only allow unique @key in hashtables, if the same @key has existed
+ * in hashtables, it will return with fails.
+ */
+void* lustre_hash_findadd_unique(struct lustre_class_hash_body *hash_body,
+ void *key, struct hlist_node *actual_hnode)
+{
+ int hashent;
+ struct lustre_hash_bucket *bucket = NULL;
+ struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
+ struct hlist_node * hash_item_hnode = NULL;
+ void *obj;
+ ENTRY;
+
+ LASSERT(hlist_unhashed(actual_hnode));
+ hashent = hop->lustre_hashfn(hash_body, key);
+
+ /* get the hash-bucket and lock it */
+ bucket = &hash_body->lchb_hash_tables[hashent];
+ spin_lock(&bucket->lhb_lock);
+
+ hash_item_hnode = lustre_hash_getitem_in_bucket_nolock(hash_body,
+ hashent, key);
+ if ( hash_item_hnode != NULL) {
+ /* the added-item exist in hashtables, so cannot add it again */
+ obj = hop->lustre_hash_object_refcount_get(hash_item_hnode);
+ spin_unlock(&bucket->lhb_lock);
+ RETURN(obj);
+ }
+
+ hlist_add_head(actual_hnode, &(bucket->lhb_head));
+
+#ifdef LUSTRE_HASH_DEBUG
+ /* hash distribute debug */
+ hash_body->lchb_hash_tables[hashent].lhb_item_count++;
+ CDEBUG(D_INFO, "hashname[%s] bucket[%d] has [%d] hashitem\n",
+ hash_body->hashname, hashent,
+ hash_body->lchb_hash_tables[hashent].lhb_item_count);
+#endif
+ obj = hop->lustre_hash_object_refcount_get(actual_hnode);
+
+ spin_unlock(&bucket->lhb_lock);
+
+ RETURN(obj);
+}
+EXPORT_SYMBOL(lustre_hash_findadd_unique);
+
+/*
* this version of additem, it allow multi same @key <key, value> in hashtables.
* in this additem version, we don't need to check if exist same @key in hash
* tables, we only add it to related hashbucket.
}
EXPORT_SYMBOL(lustre_hash_delitem);
+void lustre_hash_bucket_iterate(struct lustre_class_hash_body *hash_body,
+ void *key, hash_item_iterate_cb func, void *data)
+{
+ int hashent, find = 0;
+ struct lustre_hash_bucket *bucket = NULL;
+ struct hlist_node *hash_item_node = NULL;
+ struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
+ struct obd_export *tmp = NULL;
+
+ ENTRY;
+
+ hashent = hop->lustre_hashfn(hash_body, key);
+ bucket = &hash_body->lchb_hash_tables[hashent];
+
+ spin_lock(&bucket->lhb_lock);
+ hlist_for_each(hash_item_node, &(bucket->lhb_head)) {
+ find = hop->lustre_hash_key_compare(key, hash_item_node);
+ if (find) {
+ tmp = hop->lustre_hash_object_refcount_get(hash_item_node);
+ func(tmp, data);
+ hop->lustre_hash_object_refcount_put(hash_item_node);
+ }
+ }
+ spin_unlock(&bucket->lhb_lock);
+}
+EXPORT_SYMBOL(lustre_hash_bucket_iterate);
+
+void lustre_hash_iterate_all(struct lustre_class_hash_body *hash_body,
+ hash_item_iterate_cb func, void *data)
+{
+ int i;
+ struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
+ ENTRY;
+
+ for( i = 0; i < hash_body->lchb_hash_max_size; i++ ) {
+ struct lustre_hash_bucket * bucket;
+ struct hlist_node * actual_hnode, *pos;
+ void *obj;
+
+ bucket = &hash_body->lchb_hash_tables[i];
+#ifdef LUSTRE_HASH_DEBUG
+ CDEBUG(D_INFO, "idx %d - bucket %p\n", i, bucket);
+#endif
+ spin_lock(&bucket->lhb_lock); /* lock the bucket */
+ hlist_for_each_safe(actual_hnode, pos, &(bucket->lhb_head)) {
+ obj = hop->lustre_hash_object_refcount_get(actual_hnode);
+ func(obj, data);
+ hop->lustre_hash_object_refcount_put(actual_hnode);
+ }
+ spin_unlock(&bucket->lhb_lock);
+ }
+ EXIT;
+}
+EXPORT_SYMBOL(lustre_hash_iterate_all);
+
+
void * lustre_hash_get_object_by_key(struct lustre_class_hash_body *hash_body,
void *key)
{
}
EXPORT_SYMBOL(lustre_hash_get_object_by_key);
+/* string hashing using djb2 hash algorithm */
+__u32 djb2_hashfn(struct lustre_class_hash_body *hash_body, void* key,
+ size_t size)
+{
+ __u32 hash = 5381;
+ int i;
+ char *ptr = key;
+
+ LASSERT(key != NULL);
+
+ for( i = 0; i < size; i++ )
+ hash = hash * 33 + ptr[i];
+
+ hash &= (hash_body->lchb_hash_max_size - 1);
+
+ RETURN(hash);
+}
+
/*
* define (uuid <-> export) hash operations and function define
*/
.lustre_hash_object_refcount_put = uuid_export_refcount_put,
};
-/* string hashing using djb2 hash algorithm */
__u32 uuid_hashfn(struct lustre_class_hash_body *hash_body, void * key)
{
- __u32 hash = 5381;
- struct obd_uuid * uuid_key = NULL;
- int c;
- char *ptr = NULL;
-
- LASSERT(key != NULL);
+ struct obd_uuid * uuid_key = key;
- uuid_key = (struct obd_uuid*)key;
- ptr = uuid_key->uuid;
-
- while ((c = *ptr++)) {
- hash = hash * 33 + c;
- }
-
- hash &= (hash_body->lchb_hash_max_size - 1);
-
- RETURN(hash);
+ return djb2_hashfn(hash_body, uuid_key->uuid, sizeof(uuid_key->uuid));
}
/* Note, it is impossible to find an export that is in failed state with
.lustre_hash_object_refcount_put = nid_export_refcount_put,
};
-/* string hashing using djb2 hash algorithm */
__u32 nid_hashfn(struct lustre_class_hash_body *hash_body, void * key)
{
- __u32 hash = 5381;
- int i;
- char *ptr = key;
-
- LASSERT(key != NULL);
-
- for(i = 0 ; i < sizeof(lnet_nid_t) ; i ++)
- hash = hash * 33 + ptr[i];
-
- hash &= (hash_body->lchb_hash_max_size - 1);
-
- RETURN(hash);
+ return djb2_hashfn(hash_body, key, sizeof(lnet_nid_t));
}
/* Note, it is impossible to find an export that is in failed state with
};
EXPORT_SYMBOL(conn_hash_operations);
-/* string hashing using djb2 hash algorithm */
__u32 conn_hashfn(struct lustre_class_hash_body *hash_body, void * key)
{
- __u32 hash = 5381;
- char *ptr = key;
- int i;
-
- LASSERT(key != NULL);
-
- for(i = 0 ; i < sizeof(lnet_process_id_t) ; i ++)
- hash = hash * 33 + ptr[i];
-
- hash &= (hash_body->lchb_hash_max_size - 1);
-
- RETURN(hash);
+ return djb2_hashfn(hash_body, key, sizeof(lnet_process_id_t));
}
int conn_hash_key_compare(void *key, struct hlist_node *compared_hnode)
atomic_dec(&c->c_refcount);
}
+/*******************************************************************************/
+/* ( nid<>nidstats ) hash operations define */
+
+struct lustre_hash_operations nid_stat_hash_operations = {
+ .lustre_hashfn = nid_hashfn,
+ .lustre_hash_key_compare = nidstats_hash_key_compare,
+ .lustre_hash_object_refcount_get = nidstats_refcount_get,
+ .lustre_hash_object_refcount_put = nidstats_refcount_put,
+};
+EXPORT_SYMBOL(nid_stat_hash_operations);
+
+int nidstats_hash_key_compare(void *key, struct hlist_node * compared_hnode)
+{
+ struct nid_stat *data;
+ lnet_nid_t *nid_key;
+
+ LASSERT( key != NULL);
+
+ nid_key = (lnet_nid_t*)key;
+ data = hlist_entry(compared_hnode, struct nid_stat, nid_hash);
+
+ return (data->nid == *nid_key);
+}
+
+void* nidstats_refcount_get(struct hlist_node * actual_hnode)
+{
+ struct nid_stat *data;
+
+ data = hlist_entry(actual_hnode, struct nid_stat, nid_hash);
+ data->nid_exp_ref_count++;
+
+ RETURN(data);
+}
+
+void nidstats_refcount_put(struct hlist_node * actual_hnode)
+{
+ struct nid_stat *data;
+
+ data = hlist_entry(actual_hnode, struct nid_stat, nid_hash);
+ data->nid_exp_ref_count--;
+
+}
+
+/*******************************************************************************/
GOTO(ctxt_release, rc = -ENOENT);
}
- rc = obd_connect(NULL,
- &exph, mdc_obd, &uuid, NULL /* obd_connect_data */);
+ rc = obd_connect(NULL, &exph, mdc_obd, &uuid,
+ NULL /* obd_connect_data */, NULL);
if (rc) {
CERROR("6: failed to connect to MDC: %s\n", mdc_obd->obd_name);
GOTO(ctxt_release, rc);
struct proc_dir_entry *rm_entry;
struct proc_dir_entry *parent;
- if (!root)
+ if (!root)
return;
*rooth = NULL;
parent = root->parent;
LASSERT(parent != NULL);
-
+
while (1) {
while (temp->subdir != NULL)
temp = temp->subdir;
* by _lprocfs_lock. */
down_write(&_lprocfs_lock);
rm_entry->data = NULL;
- remove_proc_entry(rm_entry->name, rm_entry->parent);
+ remove_proc_entry(rm_entry->name, temp);
up_write(&_lprocfs_lock);
if (temp == parent)
break;
{
if (!obd)
return -EINVAL;
- if (obd->obd_proc_exports) {
+ if (obd->obd_proc_exports_entry) {
/* Should be no exports left */
- LASSERT(obd->obd_proc_exports->subdir == NULL);
- lprocfs_remove(&obd->obd_proc_exports);
+ LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
+ lprocfs_remove(&obd->obd_proc_exports_entry);
}
lprocfs_remove(&obd->obd_proc_entry);
return 0;
}
+void lprocfs_free_client_stats(void *obj, void *data)
+{
+ struct nid_stat *client_stat = obj;
+
+ CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
+ client_stat->nid_proc, client_stat->nid_stats,
+ client_stat->nid_brw_stats);
+
+ LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
+ client_stat->nid_exp_ref_count);
+
+ hlist_del_init(&client_stat->nid_hash);
+ list_del(&client_stat->nid_list);
+
+ if (client_stat->nid_proc)
+ lprocfs_remove(&client_stat->nid_proc);
+
+ if (client_stat->nid_stats)
+ lprocfs_free_stats(&client_stat->nid_stats);
+
+ if (client_stat->nid_brw_stats)
+ OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
+
+ OBD_FREE(client_stat, sizeof(*client_stat));
+ return;
+
+}
+
+void lprocfs_free_per_client_stats(struct obd_device *obd)
+{
+ struct nid_stat *stat;
+ ENTRY;
+
+ /* we need extra list - because hash_exit called to early */
+ while(!list_empty(&obd->obd_nid_stats)) {
+ stat = list_entry(obd->obd_nid_stats.next,
+ struct nid_stat, nid_list);
+ lprocfs_free_client_stats(stat, NULL);
+ }
+
+ EXIT;
+}
+
struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
enum lprocfs_stats_flags flags)
{
num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
for (i = 0; i < num_cpu; i++) {
- for (j = 0; j < stats->ls_num; j++) {
+ for (j = 0; j < stats->ls_num; j++) {
percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
atomic_inc(&percpu_cntr->lc_cntl.la_entry);
percpu_cntr->lc_count = 0;
return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
}
+struct exp_uuid_cb_data {
+ char *page;
+ int count;
+ int *eof;
+ int *len;
+};
+
+void lprocfs_exp_print_uuid(void *obj, void *cb_data)
+{
+ struct obd_export *exp = (struct obd_export *)obj;
+ struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
+
+ if (exp->exp_nid_stats)
+ *data->len += snprintf((data->page + *data->len),
+ data->count, "%s\n",
+ obd_uuid2str(&exp->exp_client_uuid));
+}
+
int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+ int *eof, void *data)
{
- struct obd_export *exp = (struct obd_export*)data;
- LASSERT(exp != NULL);
+ struct nid_stat *stats = (struct nid_stat *)data;
+ struct exp_uuid_cb_data cb_data;
+ struct obd_device *obd = stats->nid_obd;
+ int len = 0;
+
*eof = 1;
- return snprintf(page, count, "%s\n",
- obd_uuid2str(&exp->exp_client_uuid));
+ page[0] = '\0';
+ LASSERT(obd != NULL);
+
+ cb_data.page = page;
+ cb_data.count = count;
+ cb_data.eof = eof;
+ cb_data.len = &len;
+ lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
+ &stats->nid, lprocfs_exp_print_uuid,
+ &cb_data);
+ return (*cb_data.len);
}
-
-int lprocfs_exp_setup(struct obd_export *exp)
+
+int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ *eof = 1;
+ return snprintf(page, count, "%s\n",
+ "Write into this file to clear all nid stats and "
+ "stale nid entries");
+}
+EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
+
+void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
+{
+ struct nid_stat *client_stat = obj;
+ int i;
+ if(client_stat->nid_exp_ref_count == 1) {
+ hlist_del_init(&client_stat->nid_hash);
+ lprocfs_free_client_stats(client_stat, data);
+ OBD_FREE(client_stat, sizeof(struct nid_stat));
+ EXIT;
+ return;
+ }
+
+ /* we has reference to object - only clear data*/
+ if (client_stat->nid_stats) {
+ lprocfs_clear_stats(client_stat->nid_stats);
+ }
+ if (client_stat->nid_brw_stats) {
+ for (i = 0; i < BRW_LAST; i++)
+ lprocfs_oh_clear(&client_stat->nid_brw_stats->hist[i]);
+ }
+ EXIT;
+ return;
+}
+
+int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
{
- char name[sizeof (exp->exp_client_uuid.uuid) + 3];
- int i = 1, rc;
+ struct obd_device *obd = (struct obd_device *)data;
+ lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
+ lprocfs_free_client_stats, NULL);
+ return count;
+}
+EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
+
+int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t nid, int *newnid)
+{
+ int rc = 0;
+ struct nid_stat *tmp = NULL, *tmp1;
+ struct obd_device *obd = NULL;
ENTRY;
- if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports)
+
+ *newnid = 0;
+
+ if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
+ !exp->exp_obd->obd_nid_stats_hash_body)
RETURN(-EINVAL);
- mutex_down(&exp->exp_obd->obd_proc_exp_sem);
- sprintf(name, "%s", (char *)exp->exp_client_uuid.uuid);
- while (lprocfs_srch(exp->exp_obd->obd_proc_exports, name)) {
- /* We might add a new export before deleting the old one during
- an eviction (recovery-small 19a). Suckage. We
- could block, or come up with a new name, or just give up. */
- if (++i > 9)
- GOTO(out, rc = -EEXIST);
- sprintf(name, "%s:%d", (char *)exp->exp_client_uuid.uuid, i);
- }
- /* Create a proc entry for this export */
- exp->exp_proc = proc_mkdir(name, exp->exp_obd->obd_proc_exports);
- if (!exp->exp_proc) {
- CERROR("Error making export directory for %s\n", name);
- GOTO(out, rc = -ENOMEM);
+ if (!nid)
+ RETURN(0);
+
+ obd = exp->exp_obd;
+
+ CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
+
+ OBD_ALLOC(tmp, sizeof(struct nid_stat));
+ if (tmp == NULL)
+ RETURN(-ENOMEM);
+
+ tmp->nid = nid;
+ tmp->nid_obd = exp->exp_obd;
+ tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
+
+ tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, &nid,
+ &tmp->nid_hash);
+ CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
+ tmp1, libcfs_nid2str(nid), tmp->nid_exp_ref_count);
+
+ if (tmp1 != tmp) {
+ exp->exp_nid_stats = tmp1;
+ GOTO(destroy_new, rc = 0);
+ }
+ /* not found - create */
+ tmp->nid_proc = proc_mkdir(libcfs_nid2str(nid),
+ obd->obd_proc_exports_entry);
+ if (!tmp->nid_proc) {
+ CERROR("Error making export directory for"
+ " nid %s\n", libcfs_nid2str(nid));
+ lustre_hash_delitem(obd->obd_nid_stats_hash_body, &nid,
+ &tmp->nid_hash);
+ GOTO(destroy_new, rc = -ENOMEM);
}
- /* Always add nid and uuid */
- rc = lprocfs_add_simple(exp->exp_proc, "nid",
- lprocfs_exp_rd_nid, NULL, exp);
+ rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
+ lprocfs_exp_rd_uuid, NULL, tmp);
if (rc)
- GOTO(out, rc);
- rc = lprocfs_add_simple(exp->exp_proc, "uuid",
- lprocfs_exp_rd_uuid, NULL, exp);
- if (rc)
- GOTO(out, rc);
- /* Always add ldlm stats */
- exp->exp_ldlm_stats = lprocfs_alloc_stats(LDLM_LAST_OPC
- - LDLM_FIRST_OPC, 0);
- if (exp->exp_ldlm_stats == NULL) {
- lprocfs_remove(&exp->exp_proc);
- GOTO(out, rc = -ENOMEM);
- }
+ CWARN("Error adding the uuid file\n");
- lprocfs_counter_init(exp->exp_ldlm_stats,
- LDLM_ENQUEUE - LDLM_FIRST_OPC,
- 0, "ldlm_enqueue", "reqs");
- lprocfs_counter_init(exp->exp_ldlm_stats,
- LDLM_CONVERT - LDLM_FIRST_OPC,
- 0, "ldlm_convert", "reqs");
- lprocfs_counter_init(exp->exp_ldlm_stats,
- LDLM_CANCEL - LDLM_FIRST_OPC,
- 0, "ldlm_cancel", "reqs");
- lprocfs_counter_init(exp->exp_ldlm_stats,
- LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
- 0, "ldlm_bl_callback", "reqs");
- lprocfs_counter_init(exp->exp_ldlm_stats,
- LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
- 0, "ldlm_cp_callback", "reqs");
- lprocfs_counter_init(exp->exp_ldlm_stats,
- LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
- 0, "ldlm_gl_callback", "reqs");
- lprocfs_register_stats(exp->exp_proc, "ldlm_stats",
- exp->exp_ldlm_stats);
-out:
- mutex_up(&exp->exp_obd->obd_proc_exp_sem);
+ spin_lock(&obd->obd_nid_lock);
+ list_add(&tmp->nid_list, &obd->obd_nid_stats);
+ spin_unlock(&obd->obd_nid_lock);
+
+ exp->exp_nid_stats = tmp;
+ *newnid = 1;
+ RETURN(rc);
+
+destroy_new:
+ OBD_FREE(tmp, sizeof(struct nid_stat));
RETURN(rc);
}
int lprocfs_exp_cleanup(struct obd_export *exp)
{
- mutex_down(&exp->exp_obd->obd_proc_exp_sem);
- lprocfs_remove(&exp->exp_proc);
- lprocfs_free_stats(&exp->exp_ops_stats);
- lprocfs_free_stats(&exp->exp_ldlm_stats);
- mutex_up(&exp->exp_obd->obd_proc_exp_sem);
+ struct nid_stat *stat = exp->exp_nid_stats;
+
+ if(!stat)
+ RETURN(0);
+
+ stat->nid_exp_ref_count--;
+ CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
+
+ exp->exp_nid_stats = NULL;
return 0;
}
EXPORT_SYMBOL(lprocfs_add_vars);
EXPORT_SYMBOL(lprocfs_obd_setup);
EXPORT_SYMBOL(lprocfs_obd_cleanup);
+EXPORT_SYMBOL(lprocfs_add_simple);
+EXPORT_SYMBOL(lprocfs_free_per_client_stats);
EXPORT_SYMBOL(lprocfs_alloc_stats);
EXPORT_SYMBOL(lprocfs_free_stats);
EXPORT_SYMBOL(lprocfs_clear_stats);
CFS_INIT_LIST_HEAD(&obd->obd_exports);
CFS_INIT_LIST_HEAD(&obd->obd_exports_timed);
+ CFS_INIT_LIST_HEAD(&obd->obd_nid_stats);
+ spin_lock_init(&obd->obd_nid_lock);
spin_lock_init(&obd->obd_dev_lock);
sema_init(&obd->obd_dev_sem, 1);
- sema_init(&obd->obd_proc_exp_sem, 1);
spin_lock_init(&obd->obd_osfs_lock);
/* obd->obd_osfs_age must be set to a value in the distant
* past to guarantee a fresh statfs is fetched on mount. */
/* create an uuid-export hash body */
err = lustre_hash_init(&obd->obd_uuid_hash_body, "UUID_HASH",
128, &uuid_hash_operations);
- if (err) {
+ if (err)
GOTO(err_hash, err);
- }
/* create a nid-export hash body */
err = lustre_hash_init(&obd->obd_nid_hash_body, "NID_HASH",
if (err)
GOTO(err_hash, err);
+ /* create a nid-stats hash body */
+ err = lustre_hash_init(&obd->obd_nid_stats_hash_body, "NID_STATS",
+ 128, &nid_stat_hash_operations);
+ if (err)
+ GOTO(err_hash, err);
+
exp = class_new_export(obd, &obd->obd_uuid);
if (IS_ERR(exp))
RETURN(PTR_ERR(exp));
+
obd->obd_self_export = exp;
list_del_init(&exp->exp_obd_chain_timed);
class_export_put(exp);
err_hash:
lustre_hash_exit(&obd->obd_uuid_hash_body);
lustre_hash_exit(&obd->obd_nid_hash_body);
+ lustre_hash_exit(&obd->obd_nid_stats_hash_body);
obd->obd_starting = 0;
CERROR("setup %s failed (%d)\n", obd->obd_name, err);
RETURN(err);
/* destroy a nid-export hash body */
lustre_hash_exit(&obd->obd_nid_hash_body);
+ /* destroy a nid-stats hash body */
+ lustre_hash_exit(&obd->obd_nid_stats_hash_body);
+
/* Precleanup stage 1, we must make sure all exports (other than the
self-export) get destroyed. */
err = obd_precleanup(obd, OBD_CLEANUP_EXPORTS);
ocd.ocd_connect_flags = OBD_CONNECT_VERSION | OBD_CONNECT_FID;
ocd.ocd_version = LUSTRE_VERSION_CODE;
- rc = obd_connect(NULL, &mgc_conn, obd, &(obd->obd_uuid), &ocd);
+ rc = obd_connect(NULL, &mgc_conn, obd, &(obd->obd_uuid), &ocd, NULL);
if (rc) {
CERROR("connect failed %d\n", rc);
GOTO(out, rc);
static int echo_connect(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *obd,
- struct obd_uuid *cluuid, struct obd_connect_data *data)
+ struct obd_uuid *cluuid, struct obd_connect_data *data,
+ void *localdata)
{
data->ocd_connect_flags &= ECHO_CONNECT_SUPPORTED;
return class_connect(conn, obd, cluuid);
ocd->ocd_version = LUSTRE_VERSION_CODE;
ocd->ocd_group = FILTER_GROUP_ECHO;
- rc = obd_connect(NULL, &conn, tgt, &echo_uuid, ocd);
+ rc = obd_connect(NULL, &conn, tgt, &echo_uuid, ocd, NULL);
OBD_FREE(ocd, sizeof(*ocd));
static int echo_client_connect(const struct lu_env *env,
struct lustre_handle *conn,
struct obd_device *src, struct obd_uuid *cluuid,
- struct obd_connect_data *data)
+ struct obd_connect_data *data, void *localdata)
{
struct obd_export *exp;
int rc;
spin_lock_init(&brw_stats->hist[i].oh_lock);
}
+static int lprocfs_init_rw_stats(struct obd_device *obd,
+ struct lprocfs_stats **stats)
+{
+ int num_stats;
+
+ num_stats = (sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
+ LPROC_FILTER_LAST - 1;
+ *stats = lprocfs_alloc_stats(num_stats, 0);
+ if (*stats == NULL)
+ return -ENOMEM;
+
+ lprocfs_init_ops_stats(LPROC_FILTER_LAST, *stats);
+ lprocfs_counter_init(*stats, LPROC_FILTER_READ_BYTES,
+ LPROCFS_CNTR_AVGMINMAX, "read_bytes", "bytes");
+ lprocfs_counter_init(*stats, LPROC_FILTER_WRITE_BYTES,
+ LPROCFS_CNTR_AVGMINMAX, "write_bytes", "bytes");
+
+ return(0);
+}
+
/* brw_stats are 2128, ops are 3916, ldlm are 204, so 6248 bytes per client,
plus the procfs overhead :( */
static int filter_export_stats_init(struct obd_device *obd,
- struct obd_export *exp)
+ struct obd_export *exp,
+ lnet_nid_t client_nid)
{
struct filter_export_data *fed = &exp->exp_filter_data;
struct proc_dir_entry *brw_entry;
- int rc, num_stats;
+ int rc, newnid = 0;
ENTRY;
init_brw_stats(&fed->fed_brw_stats);
/* Self-export gets no proc entry */
RETURN(0);
- rc = lprocfs_exp_setup(exp);
+ rc = lprocfs_exp_setup(exp, client_nid, &newnid);
if (rc)
RETURN(rc);
- /* Create a per export proc entry for brw_stats */
- brw_entry = create_proc_entry("brw_stats", 0644, exp->exp_proc);
- if (brw_entry == NULL)
- RETURN(-ENOMEM);
- brw_entry->proc_fops = &filter_per_export_stats_fops;
- brw_entry->data = fed;
+ if (client_nid && newnid) {
+ struct nid_stat *tmp = exp->exp_nid_stats;
+ LASSERT(tmp != NULL);
+
+ OBD_ALLOC(tmp->nid_brw_stats, sizeof(struct brw_stats));
+ if (tmp->nid_brw_stats == NULL)
+ RETURN(-ENOMEM);
+
+ init_brw_stats(tmp->nid_brw_stats);
+
+ brw_entry = create_proc_entry("brw_stats", 0644,
+ exp->exp_nid_stats->nid_proc);
+ if (brw_entry == NULL)
+ RETURN(-ENOMEM);
+
+ brw_entry->proc_fops = &filter_per_nid_stats_fops;
+ brw_entry->data = exp->exp_nid_stats;
+
+ rc = lprocfs_init_rw_stats(obd, &exp->exp_nid_stats->nid_stats);
+ if (rc)
+ RETURN(rc);
+
+ rc = lprocfs_register_stats(tmp->nid_proc, "stats",
+ tmp->nid_stats);
+ if (rc)
+ RETURN(rc);
+ }
- /* Create a per export proc entry for ops stats */
- num_stats = (sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
- LPROC_FILTER_LAST - 1;
- exp->exp_ops_stats = lprocfs_alloc_stats(num_stats,
- LPROCFS_STATS_FLAG_NOPERCPU);
- if (exp->exp_ops_stats == NULL)
- RETURN(-ENOMEM);
- lprocfs_init_ops_stats(LPROC_FILTER_LAST, exp->exp_ops_stats);
- lprocfs_counter_init(exp->exp_ops_stats, LPROC_FILTER_READ_BYTES,
- LPROCFS_CNTR_AVGMINMAX, "read_bytes", "bytes");
- lprocfs_counter_init(exp->exp_ops_stats, LPROC_FILTER_WRITE_BYTES,
- LPROCFS_CNTR_AVGMINMAX, "write_bytes", "bytes");
- lprocfs_register_stats(exp->exp_proc, "stats", exp->exp_ops_stats);
RETURN(0);
}
* Otherwise, we have just read the data from the last_rcvd file and
* we know its offset. */
static int filter_client_add(struct obd_device *obd, struct obd_export *exp,
- int cl_idx)
+ int cl_idx, lnet_nid_t client_nid)
{
struct filter_obd *filter = &obd->u.filter;
struct filter_export_data *fed = &exp->exp_filter_data;
fed = &exp->exp_filter_data;
fed->fed_fcd = fcd;
fed->fed_group = le32_to_cpu(fcd->fcd_group);
- filter_export_stats_init(obd, exp);
- rc = filter_client_add(obd, exp, cl_idx);
+ filter_export_stats_init(obd, exp, 0);
+ rc = filter_client_add(obd, exp, cl_idx, 0);
/* can't fail for existing client */
LASSERTF(rc == 0, "rc = %d\n", rc);
"write_bytes", "bytes");
lproc_filter_attach_seqstat(obd);
- obd->obd_proc_exports = proc_mkdir("exports",
- obd->obd_proc_entry);
+ obd->obd_proc_exports_entry = proc_mkdir("exports",
+ obd->obd_proc_entry);
}
+ if (obd->obd_proc_exports_entry)
+ lprocfs_add_simple(obd->obd_proc_exports_entry, "clear",
+ lprocfs_nid_stats_clear_read,
+ lprocfs_nid_stats_clear_write, obd);
memcpy((void *)addr, lustre_cfg_buf(lcfg, 4),
LUSTRE_CFG_BUFLEN(lcfg, 4));
OBD_PAGE_FREE(page);
if (rc) {
- lprocfs_obd_cleanup(obd);
+ remove_proc_entry("clear", obd->obd_proc_exports_entry);
+ lprocfs_free_per_client_stats(obd);
lprocfs_free_obd_stats(obd);
+ lprocfs_obd_cleanup(obd);
}
return rc;
}
}
- lprocfs_obd_cleanup(obd);
+ remove_proc_entry("clear", obd->obd_proc_exports_entry);
+ lprocfs_free_per_client_stats(obd);
lprocfs_free_obd_stats(obd);
+ lprocfs_obd_cleanup(obd);
lquota_cleanup(filter_quota_interface_ref, obd);
/* Stop recovery before namespace cleanup. */
static int filter_connect(const struct lu_env *env,
struct lustre_handle *conn, struct obd_device *obd,
struct obd_uuid *cluuid,
- struct obd_connect_data *data)
+ struct obd_connect_data *data, void *localdata)
{
struct lvfs_run_ctxt saved;
struct obd_export *exp;
struct filter_export_data *fed;
struct filter_client_data *fcd = NULL;
+ lnet_nid_t client_nid;
__u32 group;
int rc;
ENTRY;
if (conn == NULL || obd == NULL || cluuid == NULL)
RETURN(-EINVAL);
+ if (localdata != NULL)
+ client_nid = *(lnet_nid_t *)localdata;
+ else
+ client_nid = 0ULL;
+
+
rc = class_connect(conn, obd, cluuid);
if (rc)
RETURN(rc);
if (rc)
GOTO(cleanup, rc);
- filter_export_stats_init(obd, exp);
+ filter_export_stats_init(obd, exp, client_nid);
group = data->ocd_group;
if (obd->obd_replayable) {
OBD_ALLOC(fcd, sizeof(*fcd));
memcpy(fcd->fcd_uuid, cluuid, sizeof(fcd->fcd_uuid));
fed->fed_fcd = fcd;
fed->fed_fcd->fcd_group = group;
- rc = filter_client_add(obd, exp, -1);
+ rc = filter_client_add(obd, exp, -1, client_nid);
if (rc)
GOTO(cleanup, rc);
}
#define FILTER_RECOVERY_TIMEOUT (obd_timeout * 5 * HZ / 2) /* *waves hands* */
extern struct file_operations filter_per_export_stats_fops;
+extern struct file_operations filter_per_nid_stats_fops;
/* Data stored per client in the last_rcvd file. In le32 order. */
struct filter_client_data {
lprocfs_counter_add(obd->obd_stats, LPROC_FILTER_READ_BYTES, tot_bytes);
- lprocfs_counter_add(exp->exp_ops_stats, LPROC_FILTER_READ_BYTES,
- tot_bytes);
+ if (exp->exp_nid_stats && exp->exp_nid_stats->nid_stats)
+ lprocfs_counter_add(exp->exp_nid_stats->nid_stats,
+ LPROC_FILTER_READ_BYTES, tot_bytes);
EXIT;
fsfilt_check_slow(exp->exp_obd, now, obd_timeout, "start_page_write");
- lprocfs_counter_add(exp->exp_ops_stats, LPROC_FILTER_WRITE_BYTES,
- tot_bytes);
+ if (exp->exp_nid_stats && exp->exp_nid_stats->nid_stats)
+ lprocfs_counter_add(exp->exp_nid_stats->nid_stats,
+ LPROC_FILTER_WRITE_BYTES, tot_bytes);
EXIT;
cleanup:
switch(cleanup_phase) {
lprocfs_oh_tally_log2(&obd->u.filter.fo_filter_stats.hist[BRW_R_IO_TIME],
jiffies - start_time);
lprocfs_oh_tally_log2(&exp->exp_filter_data.fed_brw_stats.hist[BRW_R_IO_TIME], jiffies - start_time);
+ if (exp->exp_nid_stats && exp->exp_nid_stats->nid_brw_stats) {
+ lprocfs_oh_tally(&exp->exp_nid_stats->nid_brw_stats->hist[BRW_R_DIO_FRAGS],
+ frags);
+ lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->hist[BRW_R_IO_TIME],
+ jiffies - start_time);
+ }
} else {
lprocfs_oh_tally(&obd->u.filter.fo_filter_stats.hist[BRW_W_DIO_FRAGS],
frags);
lprocfs_oh_tally_log2(&obd->u.filter.fo_filter_stats.hist[BRW_W_IO_TIME],
jiffies - start_time);
lprocfs_oh_tally_log2(&exp->exp_filter_data.fed_brw_stats.hist[BRW_W_IO_TIME], jiffies - start_time);
+ if (exp->exp_nid_stats && exp->exp_nid_stats->nid_brw_stats) {
+ lprocfs_oh_tally(&exp->exp_nid_stats->nid_brw_stats->hist[BRW_W_DIO_FRAGS],
+ frags);
+ lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->hist[BRW_W_IO_TIME],
+ jiffies - start_time);
+ }
}
if (rc == 0)
nr_pages);
lprocfs_oh_tally_log2(&fed->fed_brw_stats.hist[BRW_R_PAGES + wr],
nr_pages);
+ if (exp->exp_nid_stats && exp->exp_nid_stats->nid_brw_stats)
+ lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->hist[BRW_W_PAGES + wr],
+ nr_pages);
while (nr_pages-- > 0) {
if (last_page && (*pages)->index != (last_page->index + 1))
discont_blocks);
lprocfs_oh_tally(&fed->fed_brw_stats.hist[BRW_R_DISCONT_BLOCKS + wr],
discont_blocks);
+
+ if (exp->exp_nid_stats && exp->exp_nid_stats->nid_brw_stats) {
+ lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->hist[BRW_W_DISCONT_PAGES + wr],
+ discont_pages);
+ lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->hist[BRW_W_DISCONT_BLOCKS + wr],
+ discont_blocks);
+ }
}
#define pct(a,b) (b ? a * 100 / b : 0)
&brw_stats->hist[BRW_W_DISK_IOSIZE], 1);
}
+#undef pct
+
static int filter_brw_stats_seq_show(struct seq_file *seq, void *v)
{
struct obd_device *dev = seq->private;
lvars->module_vars = lprocfs_filter_module_vars;
lvars->obd_vars = lprocfs_filter_obd_vars;
}
+
+static int filter_per_nid_stats_seq_show(struct seq_file *seq, void *v)
+{
+ nid_stat_t *tmp = seq->private;
+
+ if (tmp->nid_brw_stats)
+ brw_stats_show(seq, tmp->nid_brw_stats);
+
+ return 0;
+}
+
+static ssize_t filter_per_nid_stats_seq_write(struct file *file,
+ const char *buf, size_t len,
+ loff_t *off)
+{
+ struct seq_file *seq = file->private_data;
+ nid_stat_t *tmp = seq->private;
+ int i;
+
+ if (tmp->nid_brw_stats)
+ for (i = 0; i < BRW_LAST; i++)
+ lprocfs_oh_clear(&tmp->nid_brw_stats->hist[i]);
+
+ return len;
+}
+
+LPROC_SEQ_FOPS(filter_per_nid_stats);
#endif /* LPROCFS */