X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Flod%2Flproc_lod.c;h=f748010681316f8e313faa09fcabaed062868e0e;hp=590720ad6d4bdae91e189621b7601d87ea3cde31;hb=2d15edc7be83555a7fa17a666d99b6af4922ab82;hpb=189c466ff8f7cbf6f1ebb53295f09df2ae8237a2;ds=sidebyside diff --git a/lustre/lod/lproc_lod.c b/lustre/lod/lproc_lod.c index 590720a..f748010 100644 --- a/lustre/lod/lproc_lod.c +++ b/lustre/lod/lproc_lod.c @@ -27,7 +27,7 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved * Use is subject to license terms. * - * Copyright (c) 2011,2012 Whamcloud, Inc. + * Copyright (c) 2012, 2013, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -41,24 +41,53 @@ #include "lod_internal.h" #include +/* + * Notice, all the functions below (except for lod_procfs_init() and + * lod_procfs_fini()) are not supposed to be used directly. They are + * called by Linux kernel's procfs. + */ + #ifdef LPROCFS -static int lod_rd_stripesize(char *page, char **start, off_t off, int count, - int *eof, void *data) + +/** + * Show default stripe size. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_stripesize_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device *)data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, LPU64"\n", + return seq_printf(m, LPU64"\n", lod->lod_desc.ld_default_stripe_size); } -static int lod_wr_stripesize(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set default stripe size. + * + * \param[in] file proc file + * \param[in] buffer string containing the maximum number of bytes stored in + * each object before moving to the next object in the + * layout (if any) + * \param[in] count @buffer length + * \param[in] off unused for single entry + * + * \retval @count on success + * \retval negative error code if failed + */ +static ssize_t +lod_stripesize_seq_write(struct file *file, const char *buffer, + size_t count, loff_t *off) { - struct obd_device *dev = (struct obd_device *)data; + struct seq_file *m = file->private_data; + struct obd_device *dev = m->private; struct lod_device *lod; __u64 val; int rc; @@ -73,24 +102,48 @@ static int lod_wr_stripesize(struct file *file, const char *buffer, lod->lod_desc.ld_default_stripe_size = val; return count; } +LPROC_SEQ_FOPS(lod_stripesize); -static int lod_rd_stripeoffset(char *page, char **start, off_t off, int count, - int *eof, void *data) +/** + * Show default stripe offset. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_stripeoffset_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device *)data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, LPU64"\n", + return seq_printf(m, LPU64"\n", lod->lod_desc.ld_default_stripe_offset); } -static int lod_wr_stripeoffset(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set default stripe offset. + * + * Usually contains -1 allowing Lustre to balance objects among OST + * otherwise may cause severe OST imbalance. + * + * \param[in] file proc file + * \param[in] buffer string describing starting OST index for new files + * \param[in] count @buffer length + * \param[in] off unused for single entry + * + * \retval @count on success + * \retval negative error code if failed + */ +static ssize_t +lod_stripeoffset_seq_write(struct file *file, const char *buffer, + size_t count, loff_t *off) { - struct obd_device *dev = (struct obd_device *)data; + struct seq_file *m = file->private_data; + struct obd_device *dev = m->private; struct lod_device *lod; __u64 val; int rc; @@ -104,23 +157,45 @@ static int lod_wr_stripeoffset(struct file *file, const char *buffer, lod->lod_desc.ld_default_stripe_offset = val; return count; } +LPROC_SEQ_FOPS(lod_stripeoffset); -static int lod_rd_stripetype(char *page, char **start, off_t off, int count, - int *eof, void *data) +/** + * Show default striping pattern (LOV_PATTERN_*). + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_stripetype_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device *)data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%u\n", lod->lod_desc.ld_pattern); + return seq_printf(m, "%u\n", lod->lod_desc.ld_pattern); } -static int lod_wr_stripetype(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set default striping pattern (a number, not a human-readable string). + * + * \param[in] file proc file + * \param[in] buffer string containing the default striping pattern for new + * files. This is an integer LOV_PATTERN_* value + * \param[in] count @buffer length + * \param[in] off unused for single entry + * + * \retval @count on success + * \retval negative error code if failed + */ +static ssize_t +lod_stripetype_seq_write(struct file *file, const char *buffer, + size_t count, loff_t *off) { - struct obd_device *dev = (struct obd_device *)data; + struct seq_file *m = file->private_data; + struct obd_device *dev = m->private; struct lod_device *lod; int val, rc; @@ -134,24 +209,46 @@ static int lod_wr_stripetype(struct file *file, const char *buffer, lod->lod_desc.ld_pattern = val; return count; } +LPROC_SEQ_FOPS(lod_stripetype); -static int lod_rd_stripecount(char *page, char **start, off_t off, int count, - int *eof, void *data) +/** + * Show default number of stripes. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success, + * \retval negative error code if failed + */ +static int lod_stripecount_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device *)data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%d\n", + return seq_printf(m, "%d\n", (__s16)(lod->lod_desc.ld_default_stripe_count + 1) - 1); } -static int lod_wr_stripecount(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set default number of stripes. + * + * \param[in] file proc file + * \param[in] buffer string containing the default number of stripes + * for new files + * \param[in] count @buffer length + * \param[in] off unused for single entry + * + * \retval @count on success + * \retval negative error code otherwise + */ +static ssize_t +lod_stripecount_seq_write(struct file *file, const char *buffer, + size_t count, loff_t *off) { - struct obd_device *dev = (struct obd_device *)data; + struct seq_file *m = file->private_data; + struct obd_device *dev = m->private; struct lod_device *lod; int val, rc; @@ -165,62 +262,114 @@ static int lod_wr_stripecount(struct file *file, const char *buffer, lod->lod_desc.ld_default_stripe_count = val; return count; } +LPROC_SEQ_FOPS(lod_stripecount); -static int lod_rd_numobd(char *page, char **start, off_t off, int count, - int *eof, void *data) +/** + * Show number of targets. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_numobd_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device*)data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%u\n", lod->lod_desc.ld_tgt_count); - + return seq_printf(m, "%u\n", lod->lod_desc.ld_tgt_count); } +LPROC_SEQ_FOPS_RO(lod_numobd); -static int lod_rd_activeobd(char *page, char **start, off_t off, int count, - int *eof, void *data) +/** + * Show number of active targets. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_activeobd_seq_show(struct seq_file *m, void *v) { - struct obd_device* dev = (struct obd_device*)data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%u\n", - lod->lod_desc.ld_active_tgt_count); + return seq_printf(m, "%u\n", lod->lod_desc.ld_active_tgt_count); } +LPROC_SEQ_FOPS_RO(lod_activeobd); -static int lod_rd_desc_uuid(char *page, char **start, off_t off, int count, - int *eof, void *data) +/** + * Show UUID of LOD device. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_desc_uuid_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device*) data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%s\n", lod->lod_desc.ld_uuid.uuid); + return seq_printf(m, "%s\n", lod->lod_desc.ld_uuid.uuid); } +LPROC_SEQ_FOPS_RO(lod_desc_uuid); -/* free priority (0-255): how badly user wants to choose empty osts */ -static int lod_rd_qos_priofree(char *page, char **start, off_t off, int count, - int *eof, void *data) +/** + * Show QoS priority parameter. + * + * The printed value is a percentage value (0-100%) indicating the priority + * of free space compared to performance. 0% means select OSTs equally + * regardless of their free space, 100% means select OSTs only by their free + * space even if it results in very imbalanced load on the OSTs. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_qos_priofree_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device*) data; + struct obd_device *dev = m->private; struct lod_device *lod = lu2lod_dev(dev->obd_lu_dev); LASSERT(lod != NULL); - *eof = 1; - return snprintf(page, count, "%d%%\n", + return seq_printf(m, "%d%%\n", (lod->lod_qos.lq_prio_free * 100 + 255) >> 8); } -static int lod_wr_qos_priofree(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set QoS free space priority parameter. + * + * Set the relative priority of free OST space compared to OST load when OSTs + * are space imbalanced. See lod_qos_priofree_seq_show() for description of + * this parameter. See lod_qos_thresholdrr_seq_write() and lq_threshold_rr to + * determine what constitutes "space imbalanced" OSTs. + * + * \param[in] file proc file + * \param[in] buffer string which contains the free space priority (0-100) + * \param[in] count @buffer length + * \param[in] off unused for single entry + * + * \retval @count on success + * \retval negative error code if failed + */ +static ssize_t +lod_qos_priofree_seq_write(struct file *file, const char __user *buffer, + size_t count, loff_t *off) { - struct obd_device *dev = (struct obd_device *)data; + struct seq_file *m = file->private_data; + struct obd_device *dev = m->private; struct lod_device *lod; int val, rc; @@ -238,24 +387,51 @@ static int lod_wr_qos_priofree(struct file *file, const char *buffer, lod->lod_qos.lq_reset = 1; return count; } +LPROC_SEQ_FOPS(lod_qos_priofree); -static int lod_rd_qos_thresholdrr(char *page, char **start, off_t off, - int count, int *eof, void *data) +/** + * Show threshold for "same space on all OSTs" rule. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_qos_thresholdrr_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device*) data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%d%%\n", + return seq_printf(m, "%d%%\n", (lod->lod_qos.lq_threshold_rr * 100 + 255) >> 8); } -static int lod_wr_qos_thresholdrr(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set threshold for "same space on all OSTs" rule. + * + * This sets the maximum percentage difference of free space between the most + * full and most empty OST in the currently available OSTs. If this percentage + * is exceeded, use the QoS allocator to select OSTs based on their available + * space so that more full OSTs are chosen less often, otherwise use the + * round-robin allocator for efficiency and performance. + + * \param[in] file proc file + * \param[in] buffer string containing percentage difference of free space + * \param[in] count @buffer length + * \param[in] off unused for single entry + * + * \retval @count on success + * \retval negative error code if failed + */ +static ssize_t +lod_qos_thresholdrr_seq_write(struct file *file, const char *buffer, + size_t count, loff_t *off) { - struct obd_device *dev = (struct obd_device *)data; + struct seq_file *m = file->private_data; + struct obd_device *dev = m->private; struct lod_device *lod; int val, rc; @@ -273,29 +449,52 @@ static int lod_wr_qos_thresholdrr(struct file *file, const char *buffer, lod->lod_qos.lq_dirty = 1; return count; } +LPROC_SEQ_FOPS(lod_qos_thresholdrr); -static int lod_rd_qos_maxage(char *page, char **start, off_t off, int count, - int *eof, void *data) +/** + * Show expiration period used to refresh cached statfs data, which + * is used to implement QoS/RR striping allocation algorithm. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_qos_maxage_seq_show(struct seq_file *m, void *v) { - struct obd_device *dev = (struct obd_device*) data; + struct obd_device *dev = m->private; struct lod_device *lod; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - *eof = 1; - return snprintf(page, count, "%u Sec\n", lod->lod_desc.ld_qos_maxage); + return seq_printf(m, "%u Sec\n", lod->lod_desc.ld_qos_maxage); } -static int lod_wr_qos_maxage(struct file *file, const char *buffer, - unsigned long count, void *data) +/** + * Set expiration period used to refresh cached statfs data. + * + * \param[in] file proc file + * \param[in] buffer string contains maximum age of statfs data in seconds + * \param[in] count @buffer length + * \param[in] off unused for single entry + * + * \retval @count on success + * \retval negative error code if failed + */ +static ssize_t +lod_qos_maxage_seq_write(struct file *file, const char *buffer, + size_t count, loff_t *off) { - struct obd_device *dev = (struct obd_device *)data; + struct seq_file *m = file->private_data; + struct obd_device *dev = m->private; struct lustre_cfg_bufs bufs; struct lod_device *lod; struct lu_device *next; struct lustre_cfg *lcfg; char str[32]; - int val, rc, i; + unsigned int i; + int val, rc; LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); @@ -315,18 +514,22 @@ static int lod_wr_qos_maxage(struct file *file, const char *buffer, sprintf(str, "%smaxage=%d", PARAM_OSP, val); lustre_cfg_bufs_set_string(&bufs, 1, str); lcfg = lustre_cfg_new(LCFG_PARAM, &bufs); - lod_getref(lod); + if (lcfg == NULL) + return -ENOMEM; + + lod_getref(&lod->lod_ost_descs); lod_foreach_ost(lod, i) { next = &OST_TGT(lod,i)->ltd_ost->dd_lu_dev; rc = next->ld_ops->ldo_process_config(NULL, next, lcfg); if (rc) CERROR("can't set maxage on #%d: %d\n", i, rc); } - lod_putref(lod); + lod_putref(lod, &lod->lod_ost_descs); lustre_cfg_free(lcfg); return count; } +LPROC_SEQ_FOPS(lod_qos_maxage); static void *lod_osts_seq_start(struct seq_file *p, loff_t *pos) { @@ -336,11 +539,11 @@ static void *lod_osts_seq_start(struct seq_file *p, loff_t *pos) LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - lod_getref(lod); /* released in lod_osts_seq_stop */ + lod_getref(&lod->lod_ost_descs); /* released in lod_osts_seq_stop */ if (*pos >= lod->lod_ost_bitmap->size) return NULL; - *pos = cfs_find_next_bit(lod->lod_ost_bitmap->data, + *pos = find_next_bit(lod->lod_ost_bitmap->data, lod->lod_ost_bitmap->size, *pos); if (*pos < lod->lod_ost_bitmap->size) return OST_TGT(lod,*pos); @@ -355,7 +558,7 @@ static void lod_osts_seq_stop(struct seq_file *p, void *v) LASSERT(dev != NULL); lod = lu2lod_dev(dev->obd_lu_dev); - lod_putref(lod); + lod_putref(lod, &lod->lod_ost_descs); } static void *lod_osts_seq_next(struct seq_file *p, void *v, loff_t *pos) @@ -366,7 +569,7 @@ static void *lod_osts_seq_next(struct seq_file *p, void *v, loff_t *pos) if (*pos >= lod->lod_ost_bitmap->size - 1) return NULL; - *pos = cfs_find_next_bit(lod->lod_ost_bitmap->data, + *pos = find_next_bit(lod->lod_ost_bitmap->data, lod->lod_ost_bitmap->size, *pos + 1); if (*pos < lod->lod_ost_bitmap->size) return OST_TGT(lod,*pos); @@ -374,12 +577,21 @@ static void *lod_osts_seq_next(struct seq_file *p, void *v, loff_t *pos) return NULL; } +/** + * Show active/inactive status for OST found by lod_osts_seq_next(). + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ static int lod_osts_seq_show(struct seq_file *p, void *v) { struct obd_device *obd = p->private; struct lod_ost_desc *ost_desc = v; struct lod_device *lod; - int idx, rc; + int idx, rc, active; struct dt_device *next; struct obd_statfs sfs; @@ -392,16 +604,20 @@ static int lod_osts_seq_show(struct seq_file *p, void *v) return -EINVAL; /* XXX: should be non-NULL env, but it's very expensive */ + active = 1; rc = dt_statfs(NULL, next, &sfs); - if (rc) + if (rc == -ENOTCONN) { + active = 0; + rc = 0; + } else if (rc) return rc; return seq_printf(p, "%d: %s %sACTIVE\n", idx, obd_uuid2str(&ost_desc->ltd_uuid), - sfs.os_blocks > 0 ? "" : "IN"); + active ? "" : "IN"); } -struct seq_operations lod_osts_sops = { +static const struct seq_operations lod_osts_sops = { .start = lod_osts_seq_start, .stop = lod_osts_seq_stop, .next = lod_osts_seq_next, @@ -410,61 +626,229 @@ struct seq_operations lod_osts_sops = { static int lod_osts_seq_open(struct inode *inode, struct file *file) { - struct proc_dir_entry *dp = PDE(inode); struct seq_file *seq; int rc; - LPROCFS_ENTRY_AND_CHECK(dp); rc = seq_open(file, &lod_osts_sops); - if (rc) { - LPROCFS_EXIT(); + if (rc) return rc; - } seq = file->private_data; - seq->private = dp->data; + seq->private = PDE_DATA(inode); return 0; } -struct lprocfs_vars lprocfs_lod_obd_vars[] = { - { "uuid", lprocfs_rd_uuid, 0, 0 }, - { "stripesize", lod_rd_stripesize, lod_wr_stripesize, 0 }, - { "stripeoffset", lod_rd_stripeoffset, lod_wr_stripeoffset, 0 }, - { "stripecount", lod_rd_stripecount, lod_wr_stripecount, 0 }, - { "stripetype", lod_rd_stripetype, lod_wr_stripetype, 0 }, - { "numobd", lod_rd_numobd, 0, 0 }, - { "activeobd", lod_rd_activeobd, 0, 0 }, - { "filestotal", lprocfs_rd_filestotal, 0, 0 }, - { "filesfree", lprocfs_rd_filesfree, 0, 0 }, - /*{ "filegroups", lprocfs_rd_filegroups, 0, 0 },*/ - { "blocksize", lprocfs_rd_blksize, 0, 0 }, - { "kbytestotal", lprocfs_rd_kbytestotal, 0, 0 }, - { "kbytesfree", lprocfs_rd_kbytesfree, 0, 0 }, - { "kbytesavail", lprocfs_rd_kbytesavail, 0, 0 }, - { "desc_uuid", lod_rd_desc_uuid, 0, 0 }, - { "qos_prio_free",lod_rd_qos_priofree, lod_wr_qos_priofree, 0 }, - { "qos_threshold_rr", lod_rd_qos_thresholdrr, lod_wr_qos_thresholdrr, 0 }, - { "qos_maxage", lod_rd_qos_maxage, lod_wr_qos_maxage, 0 }, +LPROC_SEQ_FOPS_RO_TYPE(lod, uuid); + +LPROC_SEQ_FOPS_RO_TYPE(lod, dt_blksize); +LPROC_SEQ_FOPS_RO_TYPE(lod, dt_kbytestotal); +LPROC_SEQ_FOPS_RO_TYPE(lod, dt_kbytesfree); +LPROC_SEQ_FOPS_RO_TYPE(lod, dt_kbytesavail); +LPROC_SEQ_FOPS_RO_TYPE(lod, dt_filestotal); +LPROC_SEQ_FOPS_RO_TYPE(lod, dt_filesfree); + +/** + * Show whether special failout mode for testing is enabled or not. + * + * \param[in] m seq file + * \param[in] v unused for single entry + * + * \retval 0 on success + * \retval negative error code if failed + */ +static int lod_lmv_failout_seq_show(struct seq_file *m, void *v) +{ + struct obd_device *dev = m->private; + struct lod_device *lod; + + LASSERT(dev != NULL); + lod = lu2lod_dev(dev->obd_lu_dev); + + return seq_printf(m, "%d\n", lod->lod_lmv_failout ? 1 : 0); +} + +/** + * Enable/disable a special failout mode for testing. + * + * This determines whether the LMV will try to continue processing a striped + * directory even if it has a (partly) corrupted entry in the master directory, + * or if it will abort upon finding a corrupted slave directory entry. + * + * \param[in] file proc file + * \param[in] buffer string: 0 or non-zero to disable or enable LMV failout + * \param[in] count @buffer length + * \param[in] off unused for single entry + * + * \retval @count on success + * \retval negative error code if failed + */ +static ssize_t +lod_lmv_failout_seq_write(struct file *file, const char *buffer, + size_t count, loff_t *off) +{ + struct seq_file *m = file->private_data; + struct obd_device *dev = m->private; + struct lod_device *lod; + int val = 0; + int rc; + + LASSERT(dev != NULL); + lod = lu2lod_dev(dev->obd_lu_dev); + + rc = lprocfs_write_helper(buffer, count, &val); + if (rc != 0) + return rc; + + if (val != 0) + lod->lod_lmv_failout = 1; + else + lod->lod_lmv_failout = 0; + + return count; +} +LPROC_SEQ_FOPS(lod_lmv_failout); + +static struct lprocfs_seq_vars lprocfs_lod_obd_vars[] = { + { .name = "uuid", + .fops = &lod_uuid_fops }, + { .name = "stripesize", + .fops = &lod_stripesize_fops }, + { .name = "stripeoffset", + .fops = &lod_stripeoffset_fops }, + { .name = "stripecount", + .fops = &lod_stripecount_fops }, + { .name = "stripetype", + .fops = &lod_stripetype_fops }, + { .name = "numobd", + .fops = &lod_numobd_fops }, + { .name = "activeobd", + .fops = &lod_activeobd_fops }, + { .name = "desc_uuid", + .fops = &lod_desc_uuid_fops }, + { .name = "qos_prio_free", + .fops = &lod_qos_priofree_fops }, + { .name = "qos_threshold_rr", + .fops = &lod_qos_thresholdrr_fops }, + { .name = "qos_maxage", + .fops = &lod_qos_maxage_fops }, + { .name = "lmv_failout", + .fops = &lod_lmv_failout_fops }, { 0 } }; -static struct lprocfs_vars lprocfs_lod_module_vars[] = { - { "num_refs", lprocfs_rd_numrefs, 0, 0 }, +static struct lprocfs_seq_vars lprocfs_lod_osd_vars[] = { + { "blocksize", &lod_dt_blksize_fops }, + { "kbytestotal", &lod_dt_kbytestotal_fops }, + { "kbytesfree", &lod_dt_kbytesfree_fops }, + { "kbytesavail", &lod_dt_kbytesavail_fops }, + { "filestotal", &lod_dt_filestotal_fops }, + { "filesfree", &lod_dt_filesfree_fops }, { 0 } }; -void lprocfs_lod_init_vars(struct lprocfs_static_vars *lvars) -{ - lvars->module_vars = lprocfs_lod_module_vars; - lvars->obd_vars = lprocfs_lod_obd_vars; -} - -struct file_operations lod_proc_target_fops = { +static const struct file_operations lod_proc_target_fops = { .owner = THIS_MODULE, .open = lod_osts_seq_open, .read = seq_read, .llseek = seq_lseek, .release = lprocfs_seq_release, }; + +/** + * Initialize procfs entries for LOD. + * + * \param[in] lod LOD device + * + * \retval 0 on success + * \retval negative error code if failed + */ +int lod_procfs_init(struct lod_device *lod) +{ + struct obd_device *obd = lod2obd(lod); + struct proc_dir_entry *lov_proc_dir = NULL; + struct obd_type *type; + int rc; + + obd->obd_vars = lprocfs_lod_obd_vars; + rc = lprocfs_obd_setup(obd); + if (rc) { + CERROR("%s: cannot setup procfs entry: %d\n", + obd->obd_name, rc); + RETURN(rc); + } + + rc = lprocfs_seq_add_vars(obd->obd_proc_entry, lprocfs_lod_osd_vars, + &lod->lod_dt_dev); + if (rc) { + CERROR("%s: cannot setup procfs entry: %d\n", + obd->obd_name, rc); + GOTO(out, rc); + } + + rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd", + 0444, &lod_proc_target_fops, obd); + if (rc) { + CWARN("%s: Error adding the target_obd file %d\n", + obd->obd_name, rc); + GOTO(out, rc); + } + + lod->lod_pool_proc_entry = lprocfs_seq_register("pools", + obd->obd_proc_entry, + NULL, NULL); + if (IS_ERR(lod->lod_pool_proc_entry)) { + rc = PTR_ERR(lod->lod_pool_proc_entry); + lod->lod_pool_proc_entry = NULL; + CWARN("%s: Failed to create pool proc file: %d\n", + obd->obd_name, rc); + GOTO(out, rc); + } + + /* If the real LOV is present which is the case for setups + * with both server and clients on the same node then use + * the LOV's proc root */ + type = class_search_type(LUSTRE_LOV_NAME); + if (type != NULL && type->typ_procroot != NULL) + lov_proc_dir = type->typ_procroot; + else + lov_proc_dir = obd->obd_type->typ_procsym; + + if (lov_proc_dir == NULL) + RETURN(0); + + /* for compatibility we link old procfs's LOV entries to lod ones */ + lod->lod_symlink = lprocfs_add_symlink(obd->obd_name, lov_proc_dir, + "../lod/%s", obd->obd_name); + if (lod->lod_symlink == NULL) + CERROR("cannot create LOV symlink for /proc/fs/lustre/lod/%s\n", + obd->obd_name); + RETURN(0); + +out: + lprocfs_obd_cleanup(obd); + + return rc; +} + +/** + * Cleanup procfs entries registred for LOD. + * + * \param[in] lod LOD device + */ +void lod_procfs_fini(struct lod_device *lod) +{ + struct obd_device *obd = lod2obd(lod); + + if (lod->lod_symlink != NULL) + lprocfs_remove(&lod->lod_symlink); + + if (lod->lod_pool_proc_entry != NULL) { + lprocfs_remove(&lod->lod_pool_proc_entry); + lod->lod_pool_proc_entry = NULL; + } + + lprocfs_obd_cleanup(obd); +} + #endif /* LPROCFS */