X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fmdd%2Fmdd_lproc.c;h=903a6754918581a72777ba331155d41bda3d8482;hb=e9b311378cf25aeb46658f3240214bd98d45fd93;hp=2d8bc678e398dcf188dc6859c82b4a45b6453e64;hpb=6869932b552ac705f411de3362f01bd50c1f6f7d;p=fs%2Flustre-release.git diff --git a/lustre/mdd/mdd_lproc.c b/lustre/mdd/mdd_lproc.c index 2d8bc67..903a675 100644 --- a/lustre/mdd/mdd_lproc.c +++ b/lustre/mdd/mdd_lproc.c @@ -46,14 +46,16 @@ #define DEBUG_SUBSYSTEM S_MDS #include +#include #include #include #include #include #include #include - +#include #include +#include #include "mdd_internal.h" @@ -88,11 +90,12 @@ int mdd_procfs_init(struct mdd_device *mdd, const char *name) rc = lu_time_init(&mdd->mdd_stats, mdd->mdd_proc_entry, mdd_counter_names, ARRAY_SIZE(mdd_counter_names)); + EXIT; out: if (rc) mdd_procfs_fini(mdd); - return rc; + return rc; } int mdd_procfs_fini(struct mdd_device *mdd) @@ -150,8 +153,294 @@ static int lprocfs_rd_atime_diff(char *page, char **start, off_t off, return snprintf(page, count, "%lu\n", mdd->mdd_atime_diff); } + +/**** changelogs ****/ +DECLARE_CHANGELOG_NAMES; + +const char *changelog_bit2str(int bit) +{ + if (bit < CL_LAST) + return changelog_str[bit]; + return NULL; +} + +static int lprocfs_rd_changelog_mask(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct mdd_device *mdd = data; + int i = 0, rc = 0; + + *eof = 1; + while (i < CL_LAST) { + if (mdd->mdd_cl.mc_mask & (1 << i)) + rc += snprintf(page + rc, count - rc, "%s ", + changelog_str[i]); + i++; + } + return rc; +} + +static int lprocfs_wr_changelog_mask(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct mdd_device *mdd = data; + char *kernbuf; + int rc; + ENTRY; + + if (count >= CFS_PAGE_SIZE) + RETURN(-EINVAL); + OBD_ALLOC(kernbuf, CFS_PAGE_SIZE); + if (kernbuf == NULL) + RETURN(-ENOMEM); + if (copy_from_user(kernbuf, buffer, count)) + GOTO(out, rc = -EFAULT); + kernbuf[count] = 0; + + rc = libcfs_str2mask(kernbuf, changelog_bit2str, &mdd->mdd_cl.mc_mask, + CHANGELOG_MINMASK, CHANGELOG_ALLMASK); + if (rc == 0) + rc = count; +out: + OBD_FREE(kernbuf, CFS_PAGE_SIZE); + return rc; +} + +struct cucb_data { + char *page; + int count; + int idx; +}; + +static int lprocfs_changelog_users_cb(struct llog_handle *llh, + struct llog_rec_hdr *hdr, void *data) +{ + struct llog_changelog_user_rec *rec; + struct cucb_data *cucb = (struct cucb_data *)data; + + LASSERT(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN); + + rec = (struct llog_changelog_user_rec *)hdr; + + cucb->idx += snprintf(cucb->page + cucb->idx, cucb->count - cucb->idx, + CHANGELOG_USER_PREFIX"%-3d "LPU64"\n", + rec->cur_id, rec->cur_endrec); + if (cucb->idx >= cucb->count) + return -ENOSPC; + + return 0; +} + +static int lprocfs_rd_changelog_users(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct mdd_device *mdd = data; + struct llog_ctxt *ctxt; + struct cucb_data cucb; + __u64 cur; + + *eof = 1; + + ctxt = llog_get_context(mdd2obd_dev(mdd),LLOG_CHANGELOG_USER_ORIG_CTXT); + if (ctxt == NULL) + return -ENXIO; + LASSERT(ctxt->loc_handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT); + + spin_lock(&mdd->mdd_cl.mc_lock); + cur = mdd->mdd_cl.mc_index; + spin_unlock(&mdd->mdd_cl.mc_lock); + + cucb.count = count; + cucb.page = page; + cucb.idx = 0; + + cucb.idx += snprintf(cucb.page + cucb.idx, cucb.count - cucb.idx, + "current index: "LPU64"\n", cur); + + cucb.idx += snprintf(cucb.page + cucb.idx, cucb.count - cucb.idx, + "%-5s %s\n", "ID", "index"); + + llog_cat_process(ctxt->loc_handle, lprocfs_changelog_users_cb, + &cucb, 0, 0); + + llog_ctxt_put(ctxt); + return cucb.idx; +} + +/* non-seq version for direct calling by class_process_proc_param */ +static int mdd_changelog_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct mdd_device *mdd = (struct mdd_device *)data; + char kernbuf[32]; + char *end; + int rc; + + if (count > (sizeof(kernbuf) - 1)) + goto out_usage; + + count = min_t(unsigned long, count, sizeof(kernbuf)); + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + + kernbuf[count] = '\0'; + /* strip trailing newline from "echo blah" */ + if (kernbuf[count - 1] == '\n') + kernbuf[count - 1] = '\0'; + + /* Forced on/off/purge rec, independent of changelog users! */ + if (strcmp(kernbuf, "on") == 0) { + rc = mdd_changelog_on(mdd, 1); + } else if (strcmp(kernbuf, "off") == 0) { + rc = mdd_changelog_on(mdd, 0); + } else { + /* purge to an index */ + long long unsigned endrec; + + endrec = (long long)simple_strtoull(kernbuf, &end, 0); + if (end == kernbuf) + goto out_usage; + + LCONSOLE_INFO("changelog purge to %llu\n", endrec); + + rc = mdd_changelog_llog_cancel(mdd, endrec); + } + + if (rc < 0) + return rc; + return count; + +out_usage: + CWARN("changelog write usage: [on|off] | \n"); + return -EINVAL; +} + +static ssize_t mdd_changelog_seq_write(struct file *file, const char *buffer, + size_t count, loff_t *off) +{ + struct seq_file *seq = file->private_data; + struct changelog_seq_iter *csi = seq->private; + struct mdd_device *mdd = (struct mdd_device *)csi->csi_dev; + + return mdd_changelog_write(file, buffer, count, mdd); +} + +static int mdd_changelog_done(struct changelog_seq_iter *csi) +{ + struct mdd_device *mdd = (struct mdd_device *)csi->csi_dev; + int done = 0; + + spin_lock(&mdd->mdd_cl.mc_lock); + done = (csi->csi_endrec >= mdd->mdd_cl.mc_index); + spin_unlock(&mdd->mdd_cl.mc_lock); + return done; +} + +/* handle nonblocking */ +static ssize_t mdd_changelog_seq_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *seq = (struct seq_file *)file->private_data; + struct changelog_seq_iter *csi = seq->private; + int rc; + ENTRY; + + if ((file->f_flags & O_NONBLOCK) && mdd_changelog_done(csi)) + RETURN(-EAGAIN); + + csi->csi_done = 0; + rc = seq_read(file, buf, count, ppos); + RETURN(rc); +} + +/* handle nonblocking */ +static unsigned int mdd_changelog_seq_poll(struct file *file, poll_table *wait) +{ + struct seq_file *seq = (struct seq_file *)file->private_data; + struct changelog_seq_iter *csi = seq->private; + struct mdd_device *mdd = (struct mdd_device *)csi->csi_dev; + ENTRY; + + csi->csi_done = 0; + poll_wait(file, &mdd->mdd_cl.mc_waitq, wait); + if (!mdd_changelog_done(csi)) + RETURN(POLLIN | POLLRDNORM); + + RETURN(0); +} + +static int mdd_changelog_seq_open(struct inode *inode, struct file *file) +{ + struct changelog_seq_iter *csi; + struct obd_device *obd; + int rc; + ENTRY; + + rc = changelog_seq_open(inode, file, &csi); + if (rc) + RETURN(rc); + + /* The proc file is set up with mdd in data, not obd */ + obd = mdd2obd_dev((struct mdd_device *)csi->csi_dev); + csi->csi_ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT); + if (csi->csi_ctxt == NULL) { + changelog_seq_release(inode, file); + RETURN(-ENOENT); + } + /* The handle is set up in llog_obd_origin_setup */ + csi->csi_llh = csi->csi_ctxt->loc_handle; + RETURN(rc); +} + +static int mdd_changelog_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct changelog_seq_iter *csi = seq->private; + + if (csi && csi->csi_ctxt) + llog_ctxt_put(csi->csi_ctxt); + + return (changelog_seq_release(inode, file)); +} + +/* mdd changelog proc can handle nonblocking ops and writing to purge recs */ +struct file_operations mdd_changelog_fops = { + .owner = THIS_MODULE, + .open = mdd_changelog_seq_open, + .read = mdd_changelog_seq_read, + .write = mdd_changelog_seq_write, + .llseek = changelog_seq_lseek, + .poll = mdd_changelog_seq_poll, + .release = mdd_changelog_seq_release, +}; + +#ifdef HAVE_QUOTA_SUPPORT +static int mdd_lprocfs_quota_rd_type(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct mdd_device *mdd = data; + return lprocfs_quota_rd_type(page, start, off, count, eof, + mdd->mdd_obd_dev); +} + +static int mdd_lprocfs_quota_wr_type(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct mdd_device *mdd = data; + return lprocfs_quota_wr_type(file, buffer, count, mdd->mdd_obd_dev); +} +#endif + static struct lprocfs_vars lprocfs_mdd_obd_vars[] = { - { "atime_diff", lprocfs_rd_atime_diff, lprocfs_wr_atime_diff, 0 }, + { "atime_diff", lprocfs_rd_atime_diff, lprocfs_wr_atime_diff, 0 }, + { "changelog_mask", lprocfs_rd_changelog_mask, + lprocfs_wr_changelog_mask, 0 }, + { "changelog_users", lprocfs_rd_changelog_users, 0, 0}, + { "changelog", 0, mdd_changelog_write, 0, &mdd_changelog_fops, 0600 }, +#ifdef HAVE_QUOTA_SUPPORT + { "quota_type", mdd_lprocfs_quota_rd_type, + mdd_lprocfs_quota_wr_type, 0 }, +#endif { 0 } }; @@ -165,3 +454,4 @@ void lprocfs_mdd_init_vars(struct lprocfs_static_vars *lvars) lvars->module_vars = lprocfs_mdd_module_vars; lvars->obd_vars = lprocfs_mdd_obd_vars; } +