Re: [RFC v2 2/2] pmem: device flush over VIRTIO
by Pankaj Gupta
>
> On Wed, Apr 25, 2018 at 04:54:14PM +0530, Pankaj Gupta wrote:
> > This patch adds functionality to perform
> > flush from guest to hosy over VIRTIO
> > when 'ND_REGION_VIRTIO'flag is set on
> > nd_negion. Flag is set by 'virtio-pmem'
> > driver.
> >
> > Signed-off-by: Pankaj Gupta <pagupta(a)redhat.com>
> > ---
> > drivers/nvdimm/region_devs.c | 7 +++++++
> > 1 file changed, 7 insertions(+)
> >
> > diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
> > index a612be6..6c6454e 100644
> > --- a/drivers/nvdimm/region_devs.c
> > +++ b/drivers/nvdimm/region_devs.c
> > @@ -20,6 +20,7 @@
> > #include <linux/nd.h>
> > #include "nd-core.h"
> > #include "nd.h"
> > +#include <linux/virtio_pmem.h>
> >
> > /*
> > * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
> > @@ -1074,6 +1075,12 @@ void nvdimm_flush(struct nd_region *nd_region)
> > struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
> > int i, idx;
> >
> > + /* call PV device flush */
> > + if (test_bit(ND_REGION_VIRTIO, &nd_region->flags)) {
> > + virtio_pmem_flush(&nd_region->dev);
> > + return;
> > + }
>
> How does libnvdimm know when flush has completed?
>
> Callers expect the flush to be finished when nvdimm_flush() returns but
> the virtio driver has only queued the request, it hasn't waited for
> completion!
I tried to implement what nvdimm does right now. It just writes to
flush hint address to make sure data persists.
I just did not want to block guest write requests till host side
fsync completes.
Operations(write/fsync) on same file would be blocking at guest side and wait time could
be worse for operations on different guest files because all these operations would happen
ultimately on same file at host.
I think with current way, we can achieve an asynchronous queuing mechanism on cost of not
100% sure when fsync would complete but it is assured it will happen. Also, its entire block
flush.
I am open for suggestions here, this is my current thought and implementation.
Thanks,
Pankaj
2 years, 8 months
Re: [Qemu-devel] [RFC v2] qemu: Add virtio pmem device
by Pankaj Gupta
> > +static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
> > +{
> > + VirtQueueElement *elem;
> > + VirtIOPMEM *pmem = VIRTIO_PMEM(vdev);
> > + HostMemoryBackend *backend = MEMORY_BACKEND(pmem->memdev);
> > + int fd = memory_region_get_fd(&backend->mr);
> > +
> > + elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
> > + if (!elem) {
> > + return;
> > + }
> > + /* flush raw backing image */
> > + fsync(fd);
>
> fsync(2) is a blocking syscall. This can hang QEMU for an unbounded
> amount of time.
o.k. Main thread will block, agree.
>
> Please do the fsync from a thread pool. See block/file-posix.c's
> aio_worker() for an example.
Sure!
>
> > +static void virtio_pmem_get_config(VirtIODevice *vdev, uint8_t *config)
> > +{
> > + VirtIOPMEM *pmem = VIRTIO_PMEM(vdev);
> > + struct virtio_pmem_config *pmemcfg = (struct virtio_pmem_config *)
> > config;
> > +
> > + pmemcfg->start = pmem->start;
> > + pmemcfg->size = pmem->size;
>
> Endianness. Please use virtio_st*_p() instead.
sure.
>
> > +#define VIRTIO_PMEM_PLUG 0
>
> What is this?
will remove
Thanks,
Pankaj
2 years, 8 months
Re: [Qemu-devel] [RFC v2 1/2] virtio: add pmem driver
by Pankaj Gupta
> > This patch adds virtio-pmem driver for KVM
> > guest.
> >
> > Guest reads the persistent memory range
> > information from Qemu over VIRTIO and registers
> > it on nvdimm_bus. It also creates a nd_region
> > object with the persistent memory range
> > information so that existing 'nvdimm/pmem'
> > driver can reserve this into system memory map.
> > This way 'virtio-pmem' driver uses existing
> > functionality of pmem driver to register persistent
> > memory compatible for DAX capable filesystems.
> >
> > This also provides function to perform guest flush
> > over VIRTIO from 'pmem' driver when userspace
> > performs flush on DAX memory range.
> >
> > Signed-off-by: Pankaj Gupta <pagupta(a)redhat.com>
> > ---
> > drivers/virtio/Kconfig | 12 ++++
> > drivers/virtio/Makefile | 1 +
> > drivers/virtio/virtio_pmem.c | 118
> > +++++++++++++++++++++++++++++++++++++++
> > include/linux/libnvdimm.h | 4 ++
> > include/uapi/linux/virtio_ids.h | 1 +
> > include/uapi/linux/virtio_pmem.h | 58 +++++++++++++++++++
> > 6 files changed, 194 insertions(+)
> > create mode 100644 drivers/virtio/virtio_pmem.c
> > create mode 100644 include/uapi/linux/virtio_pmem.h
> >
> > diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
> > index 3589764..879335d 100644
> > --- a/drivers/virtio/Kconfig
> > +++ b/drivers/virtio/Kconfig
> > @@ -42,6 +42,18 @@ config VIRTIO_PCI_LEGACY
> >
> > If unsure, say Y.
> >
> > +config VIRTIO_PMEM
> > + tristate "Virtio pmem driver"
> > + depends on VIRTIO
> > + help
> > + This driver adds persistent memory range to nd_region and registers
> > + with nvdimm bus. NVDIMM 'pmem' driver later allocates a persistent
> > + memory range on the memory information added by this driver. In addition
> > + to this, 'virtio-pmem' driver also provides a paravirt flushing
> > interface
> > + from guest to host.
> > +
> > + If unsure, say M.
> > +
> > config VIRTIO_BALLOON
> > tristate "Virtio balloon driver"
> > depends on VIRTIO
> > diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
> > index 3a2b5c5..cbe91c6 100644
> > --- a/drivers/virtio/Makefile
> > +++ b/drivers/virtio/Makefile
> > @@ -6,3 +6,4 @@ virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
> > virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
> > obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
> > obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
> > +obj-$(CONFIG_VIRTIO_PMEM) += virtio_pmem.o
> > diff --git a/drivers/virtio/virtio_pmem.c b/drivers/virtio/virtio_pmem.c
> > new file mode 100644
> > index 0000000..0906d2d
> > --- /dev/null
> > +++ b/drivers/virtio/virtio_pmem.c
> > @@ -0,0 +1,118 @@
>
> SPDX license line? See Documentation/process/license-rules.rst.
o.k.
>
> > +/* Virtio pmem Driver
> > + *
> > + * Discovers persitent memory range information
>
> s/persitent/persistent/
>
> > + * from host and provides a virtio based flushing
> > + * interface.
> > + */
> > +
> > +#include <linux/virtio.h>
> > +#include <linux/swap.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/delay.h>
> > +#include <linux/slab.h>
> > +#include <linux/module.h>
> > +#include <linux/oom.h>
> > +#include <linux/wait.h>
> > +#include <linux/magic.h>
> > +#include <linux/virtio_pmem.h>
> > +#include <linux/libnvdimm.h>
>
> Are all these headers really needed? delay.h? oom.h?
Will remove not required ones. There are from previous
RFC where used *memremap* and other mm & block includes.
>
> > +
> > +static int init_vq(struct virtio_pmem *vpmem)
> > +{
> > + struct virtqueue *vq;
> > +
> > + /* single vq */
> > + vpmem->req_vq = vq = virtio_find_single_vq(vpmem->vdev,
> > + NULL, "flush_queue");
> > +
> > + if (IS_ERR(vq))
> > + return PTR_ERR(vq);
> > +
> > + return 0;
> > +};
> > +
> > +static int virtio_pmem_probe(struct virtio_device *vdev)
> > +{
> > + int err = 0;
> > + struct resource res;
> > + struct virtio_pmem *vpmem;
> > + struct nvdimm_bus *nvdimm_bus;
> > + struct nd_region_desc ndr_desc;
> > + int nid = dev_to_node(&vdev->dev);
> > + static struct nvdimm_bus_descriptor nd_desc;
> > +
> > + if (!vdev->config->get) {
> > + dev_err(&vdev->dev, "%s failure: config disabled\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > +
> > + vdev->priv = vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem),
> > + GFP_KERNEL);
> > + if (!vpmem) {
> > + err = -ENOMEM;
> > + goto out;
> > + }
> > +
> > + vpmem->vdev = vdev;
> > + err = init_vq(vpmem);
> > + if (err)
> > + goto out;
> > +
> > + virtio_cread(vpmem->vdev, struct virtio_pmem_config,
> > + start, &vpmem->start);
> > + virtio_cread(vpmem->vdev, struct virtio_pmem_config,
> > + size, &vpmem->size);
> > +
> > + res.start = vpmem->start;
> > + res.end = vpmem->start + vpmem->size-1;
> > +
> > + memset(&nd_desc, 0, sizeof(nd_desc));
> > + nd_desc.provider_name = "virtio-pmem";
> > + nd_desc.module = THIS_MODULE;
> > + nvdimm_bus = nvdimm_bus_register(&vdev->dev, &nd_desc);
> > +
> > + if (!nvdimm_bus)
> > + goto out_nd;
> > + dev_set_drvdata(&vdev->dev, nvdimm_bus);
> > +
> > + memset(&ndr_desc, 0, sizeof(ndr_desc));
> > + ndr_desc.res = &res;
> > + ndr_desc.numa_node = nid;
> > + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
> > + set_bit(ND_REGION_VIRTIO, &ndr_desc.flags);
> > +
> > + if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc))
> > + goto out_nd;
> > +
> > + virtio_device_ready(vdev);
> > + return 0;
> > +
> > +out_nd:
> > + nvdimm_bus_unregister(nvdimm_bus);
> > +out:
> > + dev_err(&vdev->dev, "failed to register virtio pmem memory\n");
> > + vdev->config->del_vqs(vdev);
> > + return err;
> > +}
> > +
> > +static void virtio_pmem_remove(struct virtio_device *vdev)
> > +{
> > + struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
> > +
> > + nvdimm_bus_unregister(nvdimm_bus);
> > + vdev->config->del_vqs(vdev);
> > +}
> > +
> > +static struct virtio_driver virtio_pmem_driver = {
> > + .driver.name = KBUILD_MODNAME,
> > + .driver.owner = THIS_MODULE,
> > + .id_table = id_table,
> > + .probe = virtio_pmem_probe,
> > + .remove = virtio_pmem_remove,
> > +};
> > +
> > +module_virtio_driver(virtio_pmem_driver);
> > +MODULE_DEVICE_TABLE(virtio, id_table);
> > +MODULE_DESCRIPTION("Virtio pmem driver");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
> > index 097072c..b1b7f14 100644
> > --- a/include/linux/libnvdimm.h
> > +++ b/include/linux/libnvdimm.h
> > @@ -58,6 +58,10 @@ enum {
> > * (ADR)
> > */
> > ND_REGION_PERSIST_MEMCTRL = 2,
> > + /*
> > + * region flag indicating to use VIRTIO flush interface for pmem
> > + */
> > + ND_REGION_VIRTIO = 3,
>
> Can you add a generic flush callback to libnvdimm instead? That way
> virtio and other drivers can hook in without hardcoding knowledge of
> these drivers into libnvdimm.
Sure! Working on this. Same suggestion by Dan.
>
> >
> > /* mark newly adjusted resources as requiring a label update */
> > DPA_RESOURCE_ADJUSTED = 1 << 0,
> > diff --git a/include/uapi/linux/virtio_ids.h
> > b/include/uapi/linux/virtio_ids.h
> > index 6d5c3b2..5ebd049 100644
> > --- a/include/uapi/linux/virtio_ids.h
> > +++ b/include/uapi/linux/virtio_ids.h
> > @@ -43,5 +43,6 @@
> > #define VIRTIO_ID_INPUT 18 /* virtio input */
> > #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
> > #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
> > +#define VIRTIO_ID_PMEM 21 /* virtio pmem */
> >
> > #endif /* _LINUX_VIRTIO_IDS_H */
> > diff --git a/include/uapi/linux/virtio_pmem.h
> > b/include/uapi/linux/virtio_pmem.h
> > new file mode 100644
> > index 0000000..2ec27cb
> > --- /dev/null
> > +++ b/include/uapi/linux/virtio_pmem.h
> > @@ -0,0 +1,58 @@
> > +/* Virtio pmem Driver
> > + *
> > + * Discovers persitent memory range information
>
> s/persitent/persistent/
>
> > + * from host and provides a virtio based flushing
> > + * interface.
> > + */
> > +
> > +#ifndef _LINUX_VIRTIO_PMEM_H
> > +#define _LINUX_VIRTIO_PMEM_H
> > +
> > +#include <linux/types.h>
> > +#include <linux/virtio_types.h>
> > +#include <linux/virtio_ids.h>
> > +#include <linux/virtio_config.h>
> > +#include <linux/virtio_ring.h>
> > +
> > +
> > +struct virtio_pmem_config {
> > +
> > + uint64_t start;
> > + uint64_t size;
> > +};
> > +
> > +struct virtio_pmem {
> > +
> > + struct virtio_device *vdev;
> > + struct virtqueue *req_vq;
> > +
> > + uint64_t start;
> > + uint64_t size;
> > +} __packed;
>
> This is a userspace API header file, it should contain definitions that
> userspace programs need. struct virtio_pmem is a kernel-internal struct
> that should not be in the uapi headers.
>
> Only define virtio spec structs in this header file (e.g. config space,
> request structs, etc).
o.k
>
> > +static struct virtio_device_id id_table[] = {
> > + { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
> > + { 0 },
> > +};
>
> Why is static variable in the header file?
mistake :)
>
> > +
> > +void virtio_pmem_flush(struct device *dev)
>
> This only implements flush command submission, not completion. Maybe
> the next patch will implement that but it's a little strange to only see
> half of the flush operation.
>
> Please put the whole flush operation in one patch so it can be reviewed
> easily. At this point I don't know if you've forgotten to implement
> wait for completion.
>
> > +{
>
> Why is this function body in the header file?
Because I was trying to use it from pmem module without loading
virtio_pmem driver or load it dynamically. I think adding flush function in
'nd_region' struct and set it as per region type looks better solution.
Suggested by Dan & you.
>
> > + struct scatterlist sg;
> > + struct virtio_device *vdev = dev_to_virtio(dev->parent->parent);
> > + struct virtio_pmem *vpmem = vdev->priv;
> > + char *buf = "FLUSH";
>
> I'm surprised this compiles without a warning. String literals should
> be constant but the char pointer isn't constant.
Point taken.
>
> > + int err;
> > +
> > + sg_init_one(&sg, buf, sizeof(buf));
> > +
> > + err = virtqueue_add_outbuf(vpmem->req_vq, &sg, 1, buf, GFP_KERNEL);
> > +
> > + if (err) {
> > + dev_err(&vdev->dev, "failed to send command to virtio pmem device\n");
> > + return;
> > + }
> > +
> > + virtqueue_kick(vpmem->req_vq);
>
> Is any locking necessary? Two CPUs must not invoke virtio_pmem_flush()
> at the same time. Not sure if anything guarantees this, maybe you're
> relying on libnvdimm but I haven't checked.
I thought about it to some extent, and wanted to go ahead with simple version first:
- I think file 'inode -> locking' sill is there for request on single file.
- For multiple files, our aim is to just flush the backend block image.
- Even there is collision for virt queue read/write entry it should just trigger a Qemu fsync.
We just want most recent flush to assure guest writes are synced properly.
Important point here: We are doing entire block fsync for guest virtual disk.
>
> > +};
> > +
> > +#endif
> > --
> > 2.9.3
> >
> >
>
2 years, 8 months
[PATCH] ndctl, util: add OPTION_FILENAME to parse_opt_type
by QI Fuli
This patch borrows the OPTION_FILENAME from git to ndctl to make sure
filename is correct. Some related refactoring is also included:
- adds parse_options_prefix() interface
- moves is_absolute from util/help.c to util/util.c
- adds a new file util/abspath.c
Signed-off-by: QI Fuli <qi.fuli(a)jp.fujitsu.com>
---
Makefile.am | 3 ++-
util/abspath.c | 20 ++++++++++++++++
util/help.c | 5 ----
util/parse-options.c | 55 +++++++++++++++++++++++++++++++++++++++-----
util/parse-options.h | 11 +++++++--
util/util.h | 6 +++++
6 files changed, 86 insertions(+), 14 deletions(-)
create mode 100644 util/abspath.c
diff --git a/Makefile.am b/Makefile.am
index b538b1f..e0c463a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -69,6 +69,7 @@ libutil_a_SOURCES = \
util/strbuf.c \
util/wrapper.c \
util/filter.c \
- util/bitmap.c
+ util/bitmap.c \
+ util/abspath.c
nobase_include_HEADERS = daxctl/libdaxctl.h
diff --git a/util/abspath.c b/util/abspath.c
new file mode 100644
index 0000000..0a592da
--- /dev/null
+++ b/util/abspath.c
@@ -0,0 +1,20 @@
+/* originally copied from git */
+
+#include <util/util.h>
+#include <util/strbuf.h>
+
+char *prefix_filename(const char *pfx, const char *arg)
+{
+ struct strbuf path = STRBUF_INIT;
+ size_t pfx_len = pfx ? strlen(pfx) : 0;
+
+ if (!pfx_len)
+ ;
+ else if (is_absolute_path(arg))
+ pfx_len = 0;
+ else
+ strbuf_add(&path, pfx, pfx_len);
+
+ strbuf_addstr(&path, arg);
+ return strbuf_detach(&path, NULL);
+}
diff --git a/util/help.c b/util/help.c
index 8b8f951..2d57fa1 100644
--- a/util/help.c
+++ b/util/help.c
@@ -89,11 +89,6 @@ static char *cmd_to_page(const char *cmd, char **page, const char *util_name)
return *page;
}
-static int is_absolute_path(const char *path)
-{
- return path[0] == '/';
-}
-
static const char *system_path(const char *path)
{
static const char *prefix = PREFIX;
diff --git a/util/parse-options.c b/util/parse-options.c
index 751c091..4258c85 100644
--- a/util/parse-options.c
+++ b/util/parse-options.c
@@ -50,11 +50,20 @@ static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
return 0;
}
+static void fix_filename(const char *prefix, const char **file)
+{
+ if (!file || !*file || !prefix || is_absolute_path(*file)
+ || !strcmp("-", *file))
+ return;
+ *file = prefix_filename(prefix, *file);
+}
+
static int get_value(struct parse_opt_ctx_t *p,
const struct option *opt, int flags)
{
const char *s, *arg = NULL;
const int unset = flags & OPT_UNSET;
+ int err;
if (unset && p->opt)
return opterror(opt, "takes no value", flags);
@@ -77,6 +86,7 @@ static int get_value(struct parse_opt_ctx_t *p,
case OPTION_ARGUMENT:
case OPTION_GROUP:
case OPTION_STRING:
+ case OPTION_FILENAME:
case OPTION_INTEGER:
case OPTION_UINTEGER:
case OPTION_LONG:
@@ -121,6 +131,19 @@ static int get_value(struct parse_opt_ctx_t *p,
return get_arg(p, opt, flags, (const char **)opt->value);
return 0;
+ case OPTION_FILENAME:
+ err = 0;
+ if (unset)
+ *(const char **)opt->value = NULL;
+ else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+ *(const char **)opt->value = (const char *)opt->defval;
+ else
+ err = get_arg(p, opt, flags, (const char **)opt->value);
+
+ if (!err)
+ fix_filename(p->prefix, (const char **)opt->value);
+ return err;
+
case OPTION_CALLBACK:
if (unset)
return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
@@ -339,13 +362,14 @@ static void check_typos(const char *arg, const struct option *options)
}
}
-void parse_options_start(struct parse_opt_ctx_t *ctx,
- int argc, const char **argv, int flags)
+void parse_options_start(struct parse_opt_ctx_t *ctx, int argc,
+ const char **argv, const char *prefix, int flags)
{
memset(ctx, 0, sizeof(*ctx));
ctx->argc = argc - 1;
ctx->argv = argv + 1;
ctx->out = argv;
+ ctx->prefix = prefix;
ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
ctx->flags = flags;
if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
@@ -453,8 +477,10 @@ int parse_options_end(struct parse_opt_ctx_t *ctx)
return ctx->cpidx + ctx->argc;
}
-int parse_options_subcommand(int argc, const char **argv, const struct option *options,
- const char *const subcommands[], const char *usagestr[], int flags)
+static int parse_options_subcommand_prefix(int argc, const char **argv,
+ const char *prefix, const struct option *options,
+ const char *const subcommands[],
+ const char *usagestr[], int flags)
{
struct parse_opt_ctx_t ctx;
@@ -474,7 +500,7 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
strbuf_release(&buf);
}
- parse_options_start(&ctx, argc, argv, flags);
+ parse_options_start(&ctx, argc, argv, prefix, flags);
switch (parse_options_step(&ctx, options, usagestr)) {
case PARSE_OPT_HELP:
exit(129);
@@ -503,10 +529,26 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
return parse_options_end(&ctx);
}
+int parse_options_subcommand(int argc, const char **argv,
+ const struct option *options, const char *const subcommands[],
+ const char *usagestr[], int flags)
+{
+ return parse_options_subcommand_prefix(argc, argv, NULL, options,
+ subcommands, usagestr, flags);
+}
+
+int parse_options_prefix(int argc, const char **argv, const char *prefix,
+ const struct option *options,
+ const char * const usagestr[], int flags)
+{
+ return parse_options_subcommand_prefix(argc, argv, prefix, options,
+ NULL, (const char **) usagestr, flags);
+}
+
int parse_options(int argc, const char **argv, const struct option *options,
const char * const usagestr[], int flags)
{
- return parse_options_subcommand(argc, argv, options, NULL,
+ return parse_options_subcommand_prefix(argc, argv, NULL, options, NULL,
(const char **) usagestr, flags);
}
@@ -557,6 +599,7 @@ static void print_option_help(const struct option *opts, int full)
if (opts->flags & PARSE_OPT_NOARG)
break;
/* FALLTHROUGH */
+ case OPTION_FILENAME:
case OPTION_STRING:
if (opts->argh) {
if (opts->flags & PARSE_OPT_OPTARG)
diff --git a/util/parse-options.h b/util/parse-options.h
index 6fd6b24..fc5015a 100644
--- a/util/parse-options.h
+++ b/util/parse-options.h
@@ -38,6 +38,7 @@ enum parse_opt_type {
OPTION_CALLBACK,
OPTION_U64,
OPTION_UINTEGER,
+ OPTION_FILENAME,
};
enum parse_opt_flags {
@@ -135,6 +136,7 @@ struct option {
#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
#define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
+#define OPT_FILENAME(s, l, v, a, h) { .type = OPTION_FILENAME, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
#define OPT_DATE(s, l, v, h) \
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
#define OPT_CALLBACK(s, l, v, a, h, f) \
@@ -156,6 +158,10 @@ extern int parse_options(int argc, const char **argv,
const struct option *options,
const char * const usagestr[], int flags);
+extern int parse_options_prefix(int argc, const char **argv,
+ const char *prefix, const struct option *options,
+ const char * const usagestr[], int flags);
+
extern int parse_options_subcommand(int argc, const char **argv,
const struct option *options,
const char *const subcommands[],
@@ -185,6 +191,7 @@ struct parse_opt_ctx_t {
int argc, cpidx;
const char *opt;
int flags;
+ const char *prefix;
};
extern int parse_options_usage(const char * const *usagestr,
@@ -192,8 +199,8 @@ extern int parse_options_usage(const char * const *usagestr,
const char *optstr,
bool short_opt);
-extern void parse_options_start(struct parse_opt_ctx_t *ctx,
- int argc, const char **argv, int flags);
+extern void parse_options_start(struct parse_opt_ctx_t *ctx, int argc,
+ const char **argv, const char *prefix, int flags);
extern int parse_options_step(struct parse_opt_ctx_t *ctx,
const struct option *options,
diff --git a/util/util.h b/util/util.h
index 162aade..c281e8f 100644
--- a/util/util.h
+++ b/util/util.h
@@ -79,6 +79,11 @@ static inline const char *skip_prefix(const char *str, const char *prefix)
return strncmp(str, prefix, len) ? NULL : str + len;
}
+static inline int is_absolute_path(const char *path)
+{
+ return path[0] == '/';
+}
+
void usage(const char *err) NORETURN;
void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
@@ -87,5 +92,6 @@ void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
char *xstrdup(const char *str);
void *xrealloc(void *ptr, size_t size);
int prefixcmp(const char *str, const char *prefix);
+char *prefix_filename(const char *pfx, const char *arg);
#endif /* __UTIL_H__ */
--
2.17.0.140.g0b0cc9f86
2 years, 8 months
[PATCH] ndctl, filter: fix "keyword 'all' is ignored" in util_<obj>_filter()
by QI Fuli
This is a follow up patch for commit c70adc3cf6bf ("ndctl, filter: refactor
util_<obj>_filter() to support multiple space-seperated arguments")
refactored util_<obj>_filter() to support multiple space-seperated arguments.
But, when the keyword "all" is included in space-seperated arguments,
it will be treaded as <object>'s name. This patch fixes it.
Signed-off-by: QI Fuli <qi.fuli(a)jp.fujitsu.com>
---
util/filter.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/util/filter.c b/util/filter.c
index 0d3cc02..9081a6d 100644
--- a/util/filter.c
+++ b/util/filter.c
@@ -40,6 +40,9 @@ struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
for (name = strtok_r(ident, " ", &save); name;
name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(ident, "all") == 0)
+ break;
+
bus_id = strtoul(ident, &end, 0);
if (end == ident || end[0])
bus_id = ULONG_MAX;
@@ -78,6 +81,9 @@ struct ndctl_region *util_region_filter(struct ndctl_region *region,
for (name = strtok_r(ident, " ", &save); name;
name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(ident, "all") == 0)
+ break;
+
region_id = strtoul(ident, &end, 0);
if (end == ident || end[0])
region_id = ULONG_MAX;
@@ -115,6 +121,9 @@ struct ndctl_namespace *util_namespace_filter(struct ndctl_namespace *ndns,
for (name = strtok_r(ident, " ", &save); name;
name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(ident, "all") == 0)
+ break;
+
if (strcmp(name, ndctl_namespace_get_devname(ndns)) == 0)
break;
@@ -146,6 +155,9 @@ struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm,
for (name = strtok_r(ident, " ", &save); name;
name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(ident, "all") == 0)
+ break;
+
dimm_id = strtoul(ident, &end, 0);
if (end == ident || end[0])
dimm_id = ULONG_MAX;
--
2.17.0.140.g0b0cc9f86
2 years, 8 months
转发linux-nvdimm:法律法规员工问题处理技巧
by 请您查阅信件
linux-nvdimm:1775
A.新《劳动合同法》《社会保险法》《工伤保险条例》《劳动争议调解仲裁法》实操应对策略
B.有效调岗调薪、裁员解雇及违纪问题员工处理技巧
2018年4月27--28日-----上海(A单元)
2018年5月11--12日-----广州(B单元)
2018年5月17--18日-----深圳(B单元)
2018年5月24--25日-----北京(B单元)
2018年5月28--29日-----上海(B单元)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【学员对象】董事长、总经理、副总经理、人力资源总监/经理/专员及人事行政管理人员、工会干部、法务人员及相关管理人员、相关律师等。
【费====用】3200元/1人
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●培-训-报-名-中-心:
报名咨询电话:0755-61288035 010-51661863 021-31261580
手机:18890700600 (微信同号)赵先生
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●课 程 背 景:
2008年至今,随着《劳动合同法》《劳动争议调解仲裁法》《劳动合同法实施条例》《职工带薪年休假条例》《企业职工带薪年休假实施办法》《社会保险法》《职业病防治法》《工伤保险条例》《女职工劳动保护特别规定》《企业民主管理规定》《劳动争议司法解释(三)》《劳动争议司法解释(四)》《工伤保险司法解释》《劳务派遣暂行规定》《劳动人事争议仲裁办案规则》等法律法规的相继出台或修订,全国各地的劳动争议案件出现“井喷”“爆发”等现象!近几年,沿海发达地区及一二线城市的劳动争议案件依旧“稳中有涨”“持续递增”,而内地欠发达地区及三五线城市的劳动争议案件亦日趋增多!
2008年至今,大部分的劳动争议案件均以用人单位败诉告终!这些案件充分说明,“传统式、粗放式、随便式”的人力资源管理模式已经被完全否定,已经彻底落后,已经无法适应新的形势!用人单位的人力资源法律风险无处不在,广大用人单位很有必要尽快学习相关政策法律法规,掌握防范用工风险和化解劳动争议的技能技巧,掌握证明劳动者“不合格、不胜任、严重失职、严重违纪”的实操策略,以迅速构建行之有效的劳动争议风险防范机制,以迅速杜绝或减少劳动争议的发生及败诉的概率,以重新树立与持续维护用人单位的管理权威!
综上,我们特邀请我国著名的劳动法、劳动关系与劳动争议实战专家钟永棣老师主讲此培训课程。欢迎企事业单位积极组织相关人员参加此课程!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
课 程 特 色:
稀缺性:此课程将劳动法体系和薪酬绩效管理体系紧密相结合,国内极少出现此类课程。
针对性:课程内容精选了近几年主讲老师(及其专职团队)亲自处理过的且在不少用人单位内部也曾发生过的代表性案例,这些案例完全符合中国现阶段的大环境、大气候、大趋势,极具参考性和启发性。
新颖性:除前述提及的内容外,老师将随时结合最新的劳资热点,分析最新的司法判例,分享最新的实操策略。
实战性:实战沙盘演练,学员深入思考与充分互动,老师毫不保留倾囊相授;学员把错误留在课堂,把正确的观点、方法、工具、技能带回去。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
课 程 收 益:
1、全面了解人力资源管理过程中的法律风险;
2、透彻理解与人力资源管理有关的政策法律法规;
3、深度培养预测、分析人力资源管理法律风险的思维;
4、系统掌握预防和应对法律风险的实战技能及方法工具……
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【授_课_专_家_介_绍】资_深_劳_动_法_实_战_专_家 钟永棣
国内著名劳动法、劳动关系与劳动争议实战专家;劳动仲裁员、企业劳动争议预防应对专家、高级人力资源管理师、高级劳动关系协调师;国内第一批倡导、传播、实施“国家劳动法与企业薪酬绩效管理有机整合”的先行者;国内原创型、实战型、顾问型的培训师。
现任劳律通法律顾问服务中心首席顾问、上海德禾翰通律师事务所董事顾问;兼任时代光华、深圳外商投资企业协会、广州市劳动保障学会、广州市人力资源市场服务中心、广州市就业训练中心、广东省人力资源管理协会、香港工业总会、中山大学、浙江大学、华南理工大学等200多家培训公司、行业协会、有关机构单位的长期签约讲师\特聘顾问。
钟老师精通劳动政策法律法规和劳动仲裁、诉讼程序,擅长劳动用工风险的有效预防与劳动争议案件的精准应对,善于把劳动法律法规与企业人力资源管理有机整合,通晓企业劳动争议防范机制的构建和劳动用工管理体系的修正完善。钟老师经常在客户办公现场、培训现场为客户、学员即时起草、审查、修改相关制度、合同、文书,或分析具体案件,提出精准应对思路;钟老师独到的现场的专业功底,每次都赢得广大客户、学员发自内心的好评与100%的信服!
科班出身的钟老师,2000年至今一直从事与劳动法、劳动关系与劳动争议有关的工作;曾任劳动行政部门专职劳动仲裁员,曾获“广州市优秀劳动仲裁员”称号,期间审裁劳动争议案件400多宗;多年来累计代理劳动争议500多宗,参与薪酬绩效咨询项目20多个,审查完善400多家企业的人力资源管理规章制度。个人长期担任30多家(累计200多家)企业单位的人力资源管理法律顾问;以钟老师领衔的专家队伍,长期为企事业单位提供劳动法常年顾问及各种劳资专项咨询服务,客户满意度高达95%。
2008年至今,钟老师每年授课约100-130天。钟老师将枯燥的劳动政策法规溶入实际管理案例当中,将人力资源管理与劳动法有机地整合在一起;课程内容80%为真实案例、20%为必备的重点法条;学员参与讨论、互动,课程生动有趣,深入浅出,实战型超强,让学员即时学以致用!课程满意度高达95%,众多学员均表示:“第一次听到如此实战、实用、实效的劳动法课程!钟老师非常务实、不说教、没有商业味道,终于听到了让我不再后悔的精彩课程!”
钟老师先后在《广州日报》《南方都市报》《中国社会科学报》《人力资源》《香港工业总会月刊》等报刊、杂志、媒体发表专业文章或采访稿100多篇。
钟老师曾为以下客户提供咨询、顾问、内训(非公开课)服务:中国人寿、太平人寿、华康保险、广发银行、光大银行、建设银行、农业银行、工商银行、中国邮政、国家电网、中国邮政速递、中国邮政储蓄银行、携程旅行网、中铁集团、深圳机场、黄河水电开发、中烟集团、南粤物流、新南方集团、深圳爱施德股份、合生创展、中海地产、方圆地产、珠江监理、珠江投资、蒙牛奶粉、三新地产、养生堂药业、一品红药业、广州中一药业、华东医药、河北神威药业、广药集团、香港晶苑集团、广州电信、广东旺大集团、广州江丰实业、中远物流、欧时力服装、广州岭南集团、广州蔬果集团、广东交通集团、深圳运发集团、深圳东部公交、广州无线电集团、珠海拱北口岸、比亚迪汽车、纵横天地旅行网、蛇口船务运输股份、唐山冀东水泥、风神集团、中咨工程监理、高士线业、利海集团、化建集团、深圳水务监理、新广国际集团、美的集团、江苏大全集团、沿海地产控股、深圳华侨城、广东信源集团、京城控股、三一重工、广东华农温氏畜牧股份、国药物流集团广东公司、云南煤化工集团、浙江新大集团、云南驰宏锌锗股份、广州电力系统、信昌机器、云南鸿翔药业集团、广东广电网络股份公司、广州南洋电器、广汽部件、中国十七冶集团、中国通信服务、欧普照明、中广核集团、中国能源建设集团、佳通轮胎、山东赛轮集团、成都置信集团、中国移动、周大福、山东常林集团、益海嘉里集团、建滔化工集团、施耐德……千余家企业。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
● 课 程 大 纲:
A单元内容(共2天,20个以上经典案例)
专题一:招聘入职
专题二:劳动合同订立
专题三:试用期
专题四:无固定期限劳动合同
专题五:培训、保密与竞业限制
专题六:劳动关系解除与终止
专题七:社会保险法
专题八:劳动争议处理
B单元内容(共2天,20个以上经典案例)
专题一:违纪违规问题员工处理
1.劳动者往往拒绝签收处分、解雇通知书,如何应对?
2.问题员工往往拒绝提交《检讨书》或否认违纪违规事实,企业该如何收集证据?
3.对于违纪员工,应该在什么时间内处理?
4.怎样理解“严重违反用人单位的规章制度”?
5.如何在《惩罚条例》中描述“一般违纪”、“较重违纪”及“严重违纪”?
6.怎样理解与操作“严重失职,营私舞弊,给用人单位造成重大损害”?
7.如何界定“重大损害”,“重大损害”是否必须体现为造成直接的经济损失?
8.如何追究“严重失职、严重违纪违规”者的法律责任?
9.能否直接规定“禁止兼职,否则视为严重违纪违规”?
10.直线部门经理擅自口头辞退员工,仲裁机构往往认定企业非法解雇,企业该如何做,才避免案件败诉?
11.劳动者不辞而别、无故旷工,却主张被企业口头解雇,往往得到仲裁机构的支持,企业该如何做,才避免案件败诉?
12.劳动者被行政拘留、刑事拘留、司法拘留期间,劳动关系如何处理?
13.“录音录象”证据,仲裁与法院是否采信;企业内部OA系统上的资料能否作为证据使用;电子邮件、手机短信能否作为证据使用?
专题二:绩效管理与岗位调整
1.企业单方调整岗位,员工往往可被迫解除合同并索赔经济补偿,如何规避?
2.调岗时没有书面确认,员工到新岗位工作2个月后能否要求恢复到原岗位?
3.可否对“三期内”女职工进行调岗、调薪?
4.与员工协商调岗前,需要做哪些准备工作?
5.员工认同绩效结果,为什么在“不胜任工作”引发的争议中还是败诉?
6.为什么企业根据绩效结果支付员工绩效奖金,最终被认定非法克扣工资?
7.法律上如何证明劳动者“不能胜任工作”?
8.对绩效考核不合格的员工,如何合法辞退?
9.绩效正态分布往往强制划分5%的员工为不合格者,是否合法?
10.不称职等同于不胜任工作吗?
专题三:工资福利与薪酬调整
1.工资总额包括哪些工资明细?
2.新进员工薪资管理问题及处理技巧;
3.调整工作岗位后,如何单方调薪、降薪?
4.如何通过薪酬调整处理员工失职、违纪等问题?
5.什么情况下可以扣减员工的工资?
6.值班算不算加班,如何防范风险?
7.未经单位确认,劳动者自行加班,能否主张加班费?
8.年薪制的员工能否主张加班费?
9.如何设计工资构成以降低加班费成本?
10.员工主张入职以来的加班费,如何应对?
11.员工在工作日下班后加班,能否安排补休而不支付加班费?
12.内部规定“已离职员工无权获取年终奖”,真的有效吗?
专题四:工作时间与休息休假
1.每周6天,每天7小时,究竟加班了2小时还是7小时?
2.工作日停电停工休息,能否要求员工周日上班,补回停工休息日?
3.综合工时下,法定节假日是否属于总的工作时间内?
4.病假、医疗期、工伤假的享受条件及风险管控;
5.如何预防与应对员工泡病假?
6.产假、年休假、婚丧假的享受条件及风险管控;
7.实习生、反聘人员能否享受年休假?
8.用人单位是否必须批准员工请事假?
9.请事假,当月工资是以实际出勤天数计算还是以工资总额减去缺勤天数计算?
专题五:经济补偿
1.用人单位需向劳动者支付经济补偿的情形有哪些?
2.什么情况下用人单位需支付两倍的经济补偿?
3.违法解除下是否存在代通知金?
4.劳动者可否同时向用人单位主张经济补偿和赔偿金?
5.经济补偿计算的基数及标准如何确定?
6. 解除前12个月内员工休过医疗期,其平均工资如何认定?
7.经济补偿年限最高不超过十二年的适用范围?
8.如何计算《劳动合同法》生效前后的经济补偿年限?
9.如何理解“六个月以上不满一年的,按一年计算;不满六个月的,支付半个月工资的经济补偿”?
10.劳动合同法环境下“50%额外经济补偿金”是否继续适用?
专题六:规章制度与员工手册
1.企业人力资源、劳动用工管理制度常见的误区有哪些?
2.人力资源、劳动用工管理制度应该包括哪些必备内容?
3.制定规章制度的程序要求给用人单位带来哪些风险,如何应对?
4.非国有用人单位如何组建“职工代表大会”?
5.二级单位的员工是否有义务遵守集团公司的规章制度?
6.如何公示或告知,更符合仲裁或诉讼的举证要求?
7.规章制度能否规定对员工进行经济处罚?
8.规章制度违反法律法规,劳动者可以被迫解除并索取经济补偿,如何防范?
9.规章制度与员工手册到底有什么区别?
10.规章制度与员工手册应该多长时间修改一次?
专题七:工伤保险条例
1.属于工伤范围的情形有哪些?
2.不得认定为工伤的情形有哪些?
3.员工工作应酬喝酒身亡,是否属于工伤?
4.无照驾驶与驾驶无照车辆受伤,能否认定为工伤?
5.对劳动能力鉴定结果不服,能否提起行政诉讼?
6.怎样理解“上下班途中”,怎样控制期间的风险?
7.发生工伤事故,用人单位需承担哪些费用?
8.对于第三方造成的工伤事故,劳动者能否要求用人单位支付工伤待遇又同时要求第三方支付人身伤害赔偿?
9.用人单位能否以商业保险理赔款替代职工工伤赔偿待遇?
10.发生工伤事故,双方私下和解,补偿协议该如何签订才有效?
专题八:劳务派遣与业务外包
1.新法下劳务派遣面临的主要风险有哪些?
2.劳务派遣合作协议必须注意的风险细节有哪些?
3.派遣工“第三签”时,能否要求签订无固定期限劳动合同?
4.哪些岗位可以使用派遣工,辅助性、临时性、替代性如何理解与操作?
5.新规定对于同工同酬提出哪些新要求,如何规避同工同酬风险?
6.采用劳务派遣用工方式,能否异地参保?
7.用工单位如何行使对派遣员工的退还或退换权?
8.部分劳务公司很可能面临关闭停业,原来的派遣工的劳动关系如何处理?
9.业务外包与劳务派遣的本质区别有哪些?
10.如何筛选业务外包供应商,需考察哪些细节要点?
11.用工单位如何应对派遣合作争议和劳动争议?
12.如何避免与劳务派遣工或承包方员工形成双重劳动关系?
2 years, 8 months
Re: [Qemu-devel] [RFC v2] qemu: Add virtio pmem device
by Pankaj Gupta
>
> On 04/25/2018 06:24 AM, Pankaj Gupta wrote:
> > This patch adds virtio-pmem Qemu device.
> >
> > This device presents memory address range
> > information to guest which is backed by file
> > backend type. It acts like persistent memory
> > device for KVM guest. Guest can perform read
> > and persistent write operations on this memory
> > range with the help of DAX capable filesystem.
> >
> > Persistent guest writes are assured with the
> > help of virtio based flushing interface. When
> > guest userspace space performs fsync on file
> > fd on pmem device, a flush command is send to
> > Qemu over VIRTIO and host side flush/sync is
> > done on backing image file.
> >
> > This PV device code is dependent and tested
> > with 'David Hildenbrand's ' patchset[1] to
> > map non-PCDIMM devices to guest address space.
>
> This sentence doesn't belong in git history. It is better to put
> information like this...
>
> > There is still upstream discussion on using
> > among PCI bar vs memory device, will update
> > as per concensus.
>
> s/concensus/consensus/
>
> >
> > [1] https://marc.info/?l=qemu-devel&m=152450249319168&w=2
> >
> > Signed-off-by: Pankaj Gupta <pagupta(a)redhat.com>
> > ---
>
> ...here, where it is part of the email, but not picked up by 'git am'.
I see.
Thanks!
>
>
> > +++ b/qapi/misc.json
> > @@ -2871,6 +2871,29 @@
> > }
> > }
> >
> > +##
> > +# @VirtioPMemDeviceInfo:
> > +#
> > +# VirtioPMem state information
> > +#
> > +# @id: device's ID
> > +#
> > +# @start: physical address, where device is mapped
> > +#
> > +# @size: size of memory that the device provides
> > +#
> > +# @memdev: memory backend linked with device
> > +#
> > +# Since: 2.13
> > +##
> > +{ 'struct': 'VirtioPMemDeviceInfo',
> > + 'data': { '*id': 'str',
> > + 'start': 'size',
> > + 'size': 'size',
>
> TAB damage.
o.k
>
> > + 'memdev': 'str'
> > + }
> > +}
> > +
> > ##
> > # @MemoryDeviceInfo:
> > #
> > @@ -2880,7 +2903,8 @@
> > ##
> > { 'union': 'MemoryDeviceInfo',
> > 'data': { 'dimm': 'PCDIMMDeviceInfo',
> > - 'nvdimm': 'PCDIMMDeviceInfo'
> > + 'nvdimm': 'PCDIMMDeviceInfo',
> > + 'virtio-pmem': 'VirtioPMemDeviceInfo'
> > }
> > }
> >
> >
>
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc. +1-919-301-3266
> Virtualization: qemu.org | libvirt.org
>
>
2 years, 8 months
Re: [Qemu-devel] [RFC v2] qemu: Add virtio pmem device
by Pankaj Gupta
> > Hi,
> >
> > Compile failures are because Qemu 'Memory-Device changes' are not yet
> > in qemu master. As mentioned in Qemu patch message patch is
> > dependent on 'Memeory-device' patches by 'David Hildenbrand'.
>
>
> On 04/25/2018 06:24 AM, Pankaj Gupta wrote:
> > This PV device code is dependent and tested
> > with 'David Hildenbrand's ' patchset[1] to
> > map non-PCDIMM devices to guest address space.
> > There is still upstream discussion on using
> > among PCI bar vs memory device, will update
> > as per concensus.
> >
> > [1] https://marc.info/?l=qemu-devel&m=152450249319168&w=2
>
> Then let's spell that in a way that patchew understands (since patchew
> does not know how to turn marc.info references into Message-IDs):
>
> Based-on: <20180423165126.15441-1-david(a)redhat.com>
o.k
Thank you!
>
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc. +1-919-301-3266
> Virtualization: qemu.org | libvirt.org
>
>
2 years, 8 months
[PATCH v2] ndctl, filter: refacor util_<obj>_filter() to support multiple space-seperated arguments
by QI Fuli
This patch refactors util_<obj>_filter to support multiple space-seperated
arguments. Currently, only one <object> can be filtered by <object>'s name
in util_<obj>_filter(). As a result, when users want to moniotr multiple
dimms, they have to run multiple monitor processes. This feature teachs the
util_dimm_filter() that the "ident" argument maybe a space-seperatd string
which includes multiple dimm_names. Therefore the monitor can filter
multiple dimms in one process.
Signed-off-by: QI Fuli <qi.fuli(a)jp.fujitsu.com>
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
Change log since v1:
- Removing OPT_STRING_LIST from parse-option
---
util/filter.c | 141 ++++++++++++++++++++++++++++++++------------------
1 file changed, 92 insertions(+), 49 deletions(-)
diff --git a/util/filter.c b/util/filter.c
index 6ab391a..0d3cc02 100644
--- a/util/filter.c
+++ b/util/filter.c
@@ -25,101 +25,144 @@
#define NUMA_NO_NODE (-1)
-struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *ident)
+struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
{
- char *end = NULL;
+ char *end = NULL, *ident, *save;
unsigned long bus_id, id;
- const char *provider, *devname;
+ const char *provider, *devname, *name;
- if (!ident || strcmp(ident, "all") == 0)
+ if (!__ident || strcmp(__ident, "all") == 0)
return bus;
- bus_id = strtoul(ident, &end, 0);
- if (end == ident || end[0])
- bus_id = ULONG_MAX;
+ ident = strdup(__ident);
+ if (!ident)
+ return NULL;
- provider = ndctl_bus_get_provider(bus);
- devname = ndctl_bus_get_devname(bus);
- id = ndctl_bus_get_id(bus);
+ for (name = strtok_r(ident, " ", &save); name;
+ name = strtok_r(NULL, " ", &save)) {
+ bus_id = strtoul(ident, &end, 0);
+ if (end == ident || end[0])
+ bus_id = ULONG_MAX;
- if (bus_id < ULONG_MAX && bus_id == id)
- return bus;
+ provider = ndctl_bus_get_provider(bus);
+ devname = ndctl_bus_get_devname(bus);
+ id = ndctl_bus_get_id(bus);
- if (bus_id == ULONG_MAX && (strcmp(ident, provider) == 0
- || strcmp(ident, devname) == 0))
- return bus;
+ if (bus_id < ULONG_MAX && bus_id == id)
+ break;
+ if (bus_id == ULONG_MAX && (strcmp(provider, name) == 0
+ || strcmp(devname, name) == 0))
+ break;
+ }
+ free(ident);
+
+ if (name)
+ return bus;
return NULL;
}
struct ndctl_region *util_region_filter(struct ndctl_region *region,
- const char *ident)
+ const char *__ident)
{
- char *end = NULL;
- const char *name;
+ char *end = NULL, *ident, *save;
+ const char *name, *region_name;
unsigned long region_id, id;
- if (!ident || strcmp(ident, "all") == 0)
+ if (!__ident || strcmp(__ident, "all") == 0)
return region;
- region_id = strtoul(ident, &end, 0);
- if (end == ident || end[0])
- region_id = ULONG_MAX;
+ ident = strdup(__ident);
+ if (!ident)
+ return NULL;
- name = ndctl_region_get_devname(region);
- id = ndctl_region_get_id(region);
+ for (name = strtok_r(ident, " ", &save); name;
+ name = strtok_r(NULL, " ", &save)) {
+ region_id = strtoul(ident, &end, 0);
+ if (end == ident || end[0])
+ region_id = ULONG_MAX;
- if (region_id < ULONG_MAX && region_id == id)
- return region;
+ region_name = ndctl_region_get_devname(region);
+ id = ndctl_region_get_id(region);
- if (region_id == ULONG_MAX && strcmp(ident, name) == 0)
- return region;
+ if (region_id < ULONG_MAX && region_id == id)
+ break;
+
+ if (region_id == ULONG_MAX && strcmp(region_name, name) == 0)
+ break;
+ }
+ free(ident);
+ if (name)
+ return region;
return NULL;
}
struct ndctl_namespace *util_namespace_filter(struct ndctl_namespace *ndns,
- const char *ident)
+ const char *__ident)
{
struct ndctl_region *region = ndctl_namespace_get_region(ndns);
unsigned long region_id, ndns_id;
+ const char *name;
+ char *ident, *save;
- if (!ident || strcmp(ident, "all") == 0)
+ if (!__ident || strcmp(__ident, "all") == 0)
return ndns;
- if (strcmp(ident, ndctl_namespace_get_devname(ndns)) == 0)
- return ndns;
+ ident = strdup(__ident);
+ if (!ident)
+ return NULL;
- if (sscanf(ident, "%ld.%ld", ®ion_id, &ndns_id) == 2
- && ndctl_region_get_id(region) == region_id
- && ndctl_namespace_get_id(ndns) == ndns_id)
- return ndns;
+ for (name = strtok_r(ident, " ", &save); name;
+ name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(name, ndctl_namespace_get_devname(ndns)) == 0)
+ break;
+
+ if (sscanf(name, "%ld.%ld", ®ion_id, &ndns_id) == 2
+ && ndctl_region_get_id(region) == region_id
+ && ndctl_namespace_get_id(ndns) == ndns_id)
+ break;
+ }
+ free(ident);
+ if (name)
+ return ndns;
return NULL;
}
-struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm, const char *ident)
+struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm,
+ const char *__ident)
{
- char *end = NULL;
- const char *name;
+ char *end = NULL, *ident, *save;
+ const char *name, *dimm_name;
unsigned long dimm_id, id;
- if (!ident || strcmp(ident, "all") == 0)
+ if (!__ident || strcmp(__ident, "all") == 0)
return dimm;
- dimm_id = strtoul(ident, &end, 0);
- if (end == ident || end[0])
- dimm_id = ULONG_MAX;
+ ident = strdup(__ident);
+ if (!ident)
+ return NULL;
- name = ndctl_dimm_get_devname(dimm);
- id = ndctl_dimm_get_id(dimm);
+ for (name = strtok_r(ident, " ", &save); name;
+ name = strtok_r(NULL, " ", &save)) {
+ dimm_id = strtoul(ident, &end, 0);
+ if (end == ident || end[0])
+ dimm_id = ULONG_MAX;
- if (dimm_id < ULONG_MAX && dimm_id == id)
- return dimm;
+ dimm_name = ndctl_dimm_get_devname(dimm);
+ id = ndctl_dimm_get_id(dimm);
- if (dimm_id == ULONG_MAX && strcmp(ident, name) == 0)
- return dimm;
+ if (dimm_id < ULONG_MAX && dimm_id == id)
+ break;
+
+ if (dimm_id == ULONG_MAX && strcmp(dimm_name, name) == 0)
+ break;
+ }
+ free(ident);
+ if (name)
+ return dimm;
return NULL;
}
--
2.17.0.140.g0b0cc9f86
2 years, 8 months