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_get_object_by_key(struct lustre_class_hash_body *hash_body,
void *key);
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_client_stats(struct nid_stat *stat);
+extern void lprocfs_free_per_client_stats(struct obd_device *obd);
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_client_stats(struct nid_stat *stat);
+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_client_stats(struct nid_stat *stat){}
+static inline void lprocfs_free_per_client_stats(struct obd_device *obd)
+{}
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 list_head nid_chain;
+ 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_ldlm_stats;
struct ptlrpc_connection *exp_connection;
__u32 exp_conn_cnt;
OBD_CONNECT_LRU_RESIZE;
}
+struct exp_uuid_cb_data {
+ char *page;
+ int count;
+ int *eof;
+ int *len;
+ struct obd_export *exp;
+};
+
extern struct obd_export *class_conn2export(struct lustre_handle *conn);
extern struct obd_device *class_conn2obd(struct lustre_handle *conn);
+typedef void (*hash_item_iterate_cb) (void *);
#endif /* __EXPORT_H */
int client_obd_setup(struct obd_device *obddev, obd_count len, void *buf);
int client_obd_cleanup(struct obd_device * obddev);
int client_connect_import(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);
cfs_waitq_t obd_llog_waitq;
struct list_head obd_exports;
int obd_num_exports;
+ struct list_head obd_proc_nid_list;
+ spinlock_t 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 */
} u;
/* Fields used by LProcFS */
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_stats;
struct lprocfs_stats *obd_svc_stats;
unsigned int obd_cntr_base;
- struct semaphore obd_proc_exp_sem;
atomic_t obd_evict_inprogress;
cfs_waitq_t obd_evict_inprogress_waitq;
};
* granted by the target, which are guaranteed to be a subset of flags
* asked for. If @ocd == NULL, use default parameters. */
int (*o_connect)(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)(struct obd_export *exp, struct obd_device *src,
struct obd_uuid *cluuid,
struct obd_connect_data *ocd);
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);\
}
#else
static inline int obd_connect(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;
__u64 ocf = d ? d->ocd_connect_flags : 0; /* for post-condition check */
OBD_CHECK_OP(obd, connect, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, connect);
- rc = OBP(obd, connect)(conn, obd, cluuid, d);
+ rc = OBP(obd, connect)(conn, obd, cluuid, d, localdata);
/* check that only subset is granted */
LASSERT(ergo(d != NULL,
(d->ocd_connect_flags & ocf) == d->ocd_connect_flags));
/* ->o_connect() method for client side (OSC and MDC and MGC) */
int client_connect_import(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, abort_recovery;
struct obd_connect_data *data;
int size[2] = { sizeof(struct ptlrpc_body), sizeof(*data) };
+ 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) {
rc = -EBUSY;
} else {
dont_check_exports:
- rc = obd_connect(&conn, target, &cluuid, data);
+ rc = obd_connect(&conn, target, &cluuid, data,
+ &client_nid);
}
} else {
rc = obd_reconnect(export, target, &cluuid, data);
ocd->ocd_connect_flags = OBD_CONNECT_VERSION | OBD_CONNECT_AT;
ocd->ocd_version = LUSTRE_VERSION_CODE;
- rc = obd_connect(&mgc_conn, obd, &mgc_uuid, ocd);
+ rc = obd_connect(&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(&mdc_conn, obd, &sbi->ll_sb_uuid, &ocd);
+ err = obd_connect(&mdc_conn, obd, &sbi->ll_sb_uuid, &ocd, NULL);
if (err) {
CERROR("cannot connect to %s: rc = %d\n", mdc, err);
GOTO(out_free, err);
ocd.ocd_connect_flags = OBD_CONNECT_SRVLOCK | OBD_CONNECT_REQPORTAL |
OBD_CONNECT_VERSION | OBD_CONNECT_TRUNCLOCK | OBD_CONNECT_AT;
ocd.ocd_version = LUSTRE_VERSION_CODE;
- err = obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, &ocd);
+ err = obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, &ocd, NULL);
if (err) {
CERROR("cannot connect to %s: rc = %d\n", osc, err);
GOTO(out_mdc, err);
else
sbi->ll_fop = &ll_file_operations_noflock;
- err = obd_connect(&mdc_conn, obd, &sbi->ll_sb_uuid, data);
+ err = obd_connect(&mdc_conn, obd, &sbi->ll_sb_uuid, data, NULL);
if (err == -EBUSY) {
LCONSOLE_ERROR_MSG(0x14f, "An MDT (mdc %s) is performing "
"recovery, of which this client is not a "
data->ocd_brw_size = PTLRPC_MAX_BRW_PAGES << CFS_PAGE_SHIFT;
- err = obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, data);
+ err = obd_connect(&osc_conn, obd, &sbi->ll_sb_uuid, data, NULL);
if (err == -EBUSY) {
LCONSOLE_ERROR_MSG(0x150, "An OST (osc %s) is performing "
"recovery, of which this client is not a "
/* If we don't have this then an ACL MDS will refuse the connection */
ocd.ocd_connect_flags = OBD_CONNECT_ACL;
- rc = obd_connect(&mdc_conn, obd, &mdc_uuid, &ocd);
+ rc = obd_connect(&mdc_conn, obd, &mdc_uuid, &ocd, NULL);
if (rc) {
CERROR("cannot connect to %s: rc = %d\n", mdt, rc);
GOTO(out_cleanup, rc);
RETURN(0);
}
- rc = obd_connect(&conn, tgt_obd, &lov_osc_uuid, data);
+ rc = obd_connect(&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(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;
* on the server, etc.
*/
static int mds_connect(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, abort_recovery;
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:
}
}
+static int mds_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");
+}
+
+static int mds_nid_stats_clear_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ struct list_head *nids= &obd->obd_proc_nid_list;
+ nid_stat_t *client_stat = NULL, *nxt;
+
+ spin_lock(&obd->nid_lock);
+
+ list_for_each_entry_safe (client_stat, nxt, nids, nid_chain) {
+ if (!client_stat->nid_exp_ref_count)
+ lprocfs_free_client_stats(client_stat);
+ else if (client_stat->nid_stats) {
+ lprocfs_clear_stats(client_stat->nid_stats);
+ }
+ }
+
+ spin_unlock(&obd->nid_lock);
+
+ return count;
+}
+
+
/* mount the file system (secretly). lustre_cfg parameters are:
* 1 = device
* 2 = fstype
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", mds_nid_stats_clear_read,
+ mds_nid_stats_clear_write, obd);
+
if (lcfg->lcfg_bufcount >= 4 && LUSTRE_CFG_BUFLEN(lcfg, 3) > 0) {
class_uuid_t uuid;
we just need to drop our ref */
class_export_put(mds->mds_osc_exp);
+ lprocfs_free_per_client_stats(obd);
+ remove_proc_entry("clear", obd->obd_proc_exports_entry);
lprocfs_obd_cleanup(obd);
lprocfs_free_obd_stats(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)
-{
- int rc, num_stats;
+static int mds_export_stats_init(struct obd_device *obd,
+ struct obd_export *exp,
+ lnet_nid_t client_nid)
+ {
+ int rc, num_stats, newnid;
- rc = lprocfs_exp_setup(exp);
+ rc = lprocfs_exp_setup(exp, client_nid, &newnid);
if (rc)
return rc;
- num_stats = (sizeof(*obd->obd_type->typ_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_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);
/* can't fail for existing client */
LASSERTF(rc == 0, "rc = %d\n", rc);
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);
#endif
data->ocd_version = LUSTRE_VERSION_CODE;
/* NB: lov_connect() needs to fill in .ocd_index for each OST */
- rc = obd_connect(&conn, mds->mds_osc_obd, &obd->obd_uuid, data);
+ rc = obd_connect(&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);
/* Establish a connection to the MGS.*/
static int mgs_connect(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;
}
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 = (struct obd_export *)hop->lustre_hash_object_refcount_get(
+ hash_item_node);
+ ((struct exp_uuid_cb_data *)data)->exp = tmp;
+ func(data);
+ hop->lustre_hash_object_refcount_put(hash_item_node);
+ }
+ }
+ spin_unlock(&bucket->lhb_lock);
+}
+EXPORT_SYMBOL(lustre_hash_bucket_iterate);
+
void * lustre_hash_get_object_by_key(struct lustre_class_hash_body *hash_body,
void *key)
{
GOTO(ctxt_release, rc = -ENOENT);
}
- rc = obd_connect(&exph, mdc_obd, &uuid, NULL /* obd_connect_data */);
+ rc = obd_connect(&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);
{
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(nid_stat_t *client_stat)
+{
+ LASSERT(client_stat->nid_exp_ref_count == 0);
+
+ list_del(&client_stat->nid_chain);
+
+ 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(struct nid_stat));
+ return;
+
+}
+
+void lprocfs_free_per_client_stats(struct obd_device *obd)
+{
+
+ struct list_head *nids= &obd->obd_proc_nid_list;
+ nid_stat_t *client_stat = NULL, *nxt;
+ ENTRY;
+
+ spin_lock(&obd->nid_lock);
+
+ list_for_each_entry_safe (client_stat, nxt, nids, nid_chain)
+ lprocfs_free_client_stats(client_stat);
+
+ spin_unlock(&obd->nid_lock);
+ return;
+
+}
+
struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
enum lprocfs_stats_flags flags)
{
return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
}
+void lprocfs_exp_print_uuid(void *cb_data)
+{
+ struct exp_uuid_cb_data *data = (struct exp_rd_uuid_cb_data *)cb_data;
+
+ if (data->exp->exp_nid_stats)
+ *data->len += snprintf((data->page + *data->len),
+ data->count, "%s\n",
+ obd_uuid2str(&data->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;
+ cb_data.exp = NULL;
+ 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_exp_setup(struct obd_export *exp, lnet_nid_t nid, int *newnid)
{
- char name[sizeof (exp->exp_client_uuid.uuid) + 3];
- int i = 1, rc;
+ int rc = 0;
+ struct nid_stat *tmp = NULL;
+ struct obd_device *obd = NULL;
+ struct obd_export *export = NULL;
ENTRY;
- if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports)
+ if (exp->exp_obd)
+ obd = exp->exp_obd;
+
+ if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
+ !obd->obd_nid_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);
- }
+ *newnid = 0;
- /* 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(rc);
- /* Always add nid and uuid */
- rc = lprocfs_add_simple(exp->exp_proc, "nid",
- lprocfs_exp_rd_nid, NULL, exp);
- 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);
- }
+ export = lustre_hash_get_object_by_key(obd->obd_nid_hash_body,
+ &nid);
+ if (export) {
+ exp->exp_nid_stats = export->exp_nid_stats;
+ *newnid = 0;
+ class_export_put(export);
+ } else {
+ OBD_ALLOC(tmp, sizeof(struct nid_stat));
+ if (tmp == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ tmp->nid = nid;
+ tmp->nid_obd = exp->exp_obd;
+ tmp->nid_exp_ref_count = 0;
+ tmp->nid_proc = proc_mkdir(libcfs_nid2str(nid),
+ exp->exp_obd->obd_proc_exports_entry);
+ if (!tmp->nid_proc) {
+ CERROR("Error making export directory for"
+ " nid %s\n", libcfs_nid2str(nid));
+ OBD_FREE(tmp, sizeof(struct nid_stat));
+ GOTO(out, rc = -ENOMEM);
+ }
+
+ rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
+ lprocfs_exp_rd_uuid, NULL, tmp);
+ if (rc)
+ CERROR("Error adding the uuid file\n");
+
+ exp->exp_nid_stats = tmp;
+ *newnid = 1;
- 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);
+ spin_lock(&obd->nid_lock);
+
+ list_add_tail(&tmp->nid_chain,
+ &exp->exp_obd->obd_proc_nid_list);
+
+ spin_unlock(&obd->nid_lock);
+
+ }
+ if (exp->exp_nid_stats)
+ exp->exp_nid_stats->nid_exp_ref_count++;
out:
- mutex_up(&exp->exp_obd->obd_proc_exp_sem);
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);
+ if (exp->exp_nid_stats) {
+ exp->exp_nid_stats->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_client_stats);
+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);
+ INIT_LIST_HEAD(&obd->obd_proc_nid_list);
+ spin_lock_init(&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. */
data->ocd_connect_flags = OBD_CONNECT_VERSION | OBD_CONNECT_AT;
data->ocd_version = LUSTRE_VERSION_CODE;
/* We connect to the MGS at setup, and don't disconnect until cleanup */
- rc = obd_connect(&mgc_conn, obd, &(obd->obd_uuid), data);
+ rc = obd_connect(&mgc_conn, obd, &(obd->obd_uuid), data, NULL);
OBD_FREE_PTR(data);
if (rc) {
CERROR("connect failed %d\n", rc);
};
static int echo_connect(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_connect_flags = OBD_CONNECT_VERSION | OBD_CONNECT_REQPORTAL;
ocd->ocd_version = LUSTRE_VERSION_CODE;
- rc = obd_connect(&conn, tgt, &echo_uuid, ocd);
+ rc = obd_connect(&conn, tgt, &echo_uuid, ocd, NULL);
OBD_FREE(ocd, sizeof(*ocd));
static int echo_client_connect(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_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);
if (obd_uuid_equals(&exp->exp_client_uuid, &obd->obd_uuid))
/* 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_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;
} else {
fed = &exp->exp_filter_data;
fed->fed_fcd = fcd;
- 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);
obd->u.obt.obt_sb = 0;
return rc;
}
+static int filter_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");
+}
+
+static int filter_nid_stats_clear_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ struct list_head *nids = &obd->obd_proc_nid_list;
+ nid_stat_t *client_stat = NULL, *nxt;
+ int i;
+
+ spin_lock(&obd->nid_lock);
+
+ list_for_each_entry_safe (client_stat, nxt, nids, nid_chain) {
+ if (!client_stat->nid_exp_ref_count) {
+ lprocfs_free_client_stats(client_stat);
+ } else {
+ 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]);
+ }
+ }
+
+ spin_unlock(&obd->nid_lock);
+
+ return count;
+}
static int filter_setup(struct obd_device *obd, obd_count len, void *buf)
{
LPROCFS_CNTR_AVGMINMAX,
"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",
+ filter_nid_stats_clear_read,
+ filter_nid_stats_clear_write, obd);
memcpy((void *)page, lustre_cfg_buf(lcfg, 4),
LUSTRE_CFG_BUFLEN(lcfg, 4));
}
}
+ lprocfs_free_per_client_stats(obd);
+ remove_proc_entry("clear", obd->obd_proc_exports_entry);
lprocfs_obd_cleanup(obd);
lprocfs_free_obd_stats(obd);
/* nearly identical to mds_connect */
static int filter_connect(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 obd_export *exp;
struct filter_export_data *fed;
struct filter_client_data *fcd = NULL;
+ lnet_nid_t *client_nid = (lnet_nid_t *)localdata;
int rc;
ENTRY;
if (rc)
GOTO(cleanup, rc);
- filter_export_stats_init(obd, exp);
+ filter_export_stats_init(obd, exp, *client_nid);
if (!obd->obd_replayable)
GOTO(cleanup, rc = 0);
memcpy(fcd->fcd_uuid, cluuid, sizeof(fcd->fcd_uuid));
fed->fed_fcd = fcd;
- rc = filter_client_add(obd, exp, -1);
+ rc = filter_client_add(obd, exp, -1, *client_nid);
GOTO(cleanup, rc);
#define GRANT_FOR_LLOG(obd) 16
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 {
GOTO(cleanup, rc);
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;
lprocfs_counter_add(exp->exp_obd->obd_stats, LPROC_FILTER_WRITE_BYTES,
tot_bytes);
- 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) {
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(&exp->exp_filter_data.fed_brw_stats.hist[BRW_W_DIO_FRAGS],
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)
#endif
}
+#undef pct
+
static int filter_brw_stats_seq_show(struct seq_file *seq, void *v)
{
struct obd_device *dev = seq->private;
LPROC_SEQ_FOPS(filter_per_export_stats);
LPROCFS_INIT_VARS(filter, lprocfs_module_vars, lprocfs_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 */