mirror of
git://sourceware.org/git/lvm2.git
synced 2025-02-06 01:58:01 +03:00
Enhance the management of readahead settings.
This commit is contained in:
parent
19c865437a
commit
b4068515e8
@ -1,5 +1,8 @@
|
||||
Version 2.02.29 -
|
||||
==================================
|
||||
Add activation/readahead configuration option and FMT_RESTRICTED_READAHEAD.
|
||||
Extend readahead arg to accept "auto" and "none".
|
||||
Add lv_read_ahead and lv_kernel_read_ahead fields to reports.
|
||||
Prevent lvconvert -s from using same LV as origin and snapshot.
|
||||
Fix human-readable output of odd numbers of sectors.
|
||||
Add pv_mda_free and vg_mda_free fields to reports for raw text format.
|
||||
|
@ -291,6 +291,12 @@ activation {
|
||||
# Size (in KB) of each copy operation when mirroring
|
||||
mirror_region_size = 512
|
||||
|
||||
# Setting to use when there is no readahead value stored in the metadata.
|
||||
#
|
||||
# "none" - Disable readahead.
|
||||
# "auto" - Use default value chosen by kernel.
|
||||
readahead = "auto"
|
||||
|
||||
# 'mirror_image_fault_policy' and 'mirror_log_fault_policy' define
|
||||
# how a device failure affecting a mirror is handled.
|
||||
# A mirror is composed of mirror images (copies) and a log.
|
||||
|
@ -153,6 +153,7 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
static int _process_config(struct cmd_context *cmd)
|
||||
{
|
||||
mode_t old_umask;
|
||||
const char *read_ahead;
|
||||
|
||||
/* umask */
|
||||
cmd->default_settings.umask = find_config_tree_int(cmd,
|
||||
@ -207,6 +208,16 @@ static int _process_config(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
read_ahead = find_config_tree_str(cmd, "activation/readahead", DEFAULT_READ_AHEAD);
|
||||
if (!strcasecmp(read_ahead, "auto"))
|
||||
cmd->default_settings.read_ahead = DM_READ_AHEAD_AUTO;
|
||||
else if (!strcasecmp(read_ahead, "none"))
|
||||
cmd->default_settings.read_ahead = DM_READ_AHEAD_NONE;
|
||||
else {
|
||||
log_error("Invalid readahead specification");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ struct config_info {
|
||||
int suffix;
|
||||
int archive; /* should we archive ? */
|
||||
int backup; /* should we backup ? */
|
||||
int read_ahead; /* DM_READ_AHEAD_NONE or _AUTO */
|
||||
const char *msg_prefix;
|
||||
struct format_type *fmt;
|
||||
uint64_t unit_factor;
|
||||
|
@ -63,6 +63,7 @@
|
||||
#define DEFAULT_PVMETADATASIZE 255
|
||||
#define DEFAULT_PVMETADATACOPIES 1
|
||||
#define DEFAULT_LABELSECTOR UINT64_C(1)
|
||||
#define DEFAULT_READ_AHEAD "auto"
|
||||
|
||||
#define DEFAULT_MSG_PREFIX " "
|
||||
#define DEFAULT_CMD_NAME 0
|
||||
|
@ -556,7 +556,8 @@ struct format_type *init_format(struct cmd_context *cmd)
|
||||
fmt->ops = &_format1_ops;
|
||||
fmt->name = FMT_LVM1_NAME;
|
||||
fmt->alias = NULL;
|
||||
fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE;
|
||||
fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE |
|
||||
FMT_RESTRICTED_READAHEAD;
|
||||
fmt->private = NULL;
|
||||
|
||||
if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
|
||||
|
@ -349,7 +349,11 @@ int import_lv(struct dm_pool *mem, struct logical_volume *lv, struct lv_disk *lv
|
||||
else
|
||||
lv->alloc = ALLOC_NORMAL;
|
||||
|
||||
lv->read_ahead = lvd->lv_read_ahead;
|
||||
if (!lvd->lv_read_ahead)
|
||||
lv->read_ahead = lv->vg->cmd->default_settings.read_ahead;
|
||||
else
|
||||
lv->read_ahead = lvd->lv_read_ahead;
|
||||
|
||||
lv->size = lvd->lv_size;
|
||||
lv->le_count = lvd->lv_allocated_le;
|
||||
|
||||
@ -386,7 +390,12 @@ static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
lvd->lv_dev = MKDEV(LVM_BLK_MAJOR, lvnum_from_lvid(&lv->lvid));
|
||||
}
|
||||
|
||||
lvd->lv_read_ahead = lv->read_ahead;
|
||||
if (lv->read_ahead == DM_READ_AHEAD_AUTO ||
|
||||
lv->read_ahead == DM_READ_AHEAD_NONE)
|
||||
lvd->lv_read_ahead = 0;
|
||||
else
|
||||
lvd->lv_read_ahead = lv->read_ahead;
|
||||
|
||||
lvd->lv_stripes =
|
||||
list_item(lv->segments.n, struct lv_segment)->area_count;
|
||||
lvd->lv_stripesize =
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "str_list.h"
|
||||
#include "display.h"
|
||||
#include "segtype.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
/* This file contains only imports at the moment... */
|
||||
|
||||
@ -77,7 +78,7 @@ int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem, struct list *p
|
||||
lv->size = 0;
|
||||
lv->name = NULL;
|
||||
lv->le_count = 0;
|
||||
lv->read_ahead = 0;
|
||||
lv->read_ahead = vg->cmd->default_settings.read_ahead;
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
|
@ -271,6 +271,19 @@ int out_hint(struct formatter *f, const char *fmt, ...)
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends a comment
|
||||
*/
|
||||
static int _out_comment(struct formatter *f, const char *comment, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
_out_with_comment(f, comment, fmt, ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* The normal output function.
|
||||
*/
|
||||
@ -546,8 +559,17 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
|
||||
if (lv->read_ahead)
|
||||
switch (lv->read_ahead) {
|
||||
case DM_READ_AHEAD_NONE:
|
||||
_out_comment(f, "# None", "read_ahead = -1");
|
||||
break;
|
||||
case DM_READ_AHEAD_AUTO:
|
||||
/* No output - use default */
|
||||
break;
|
||||
default:
|
||||
outf(f, "read_ahead = %u", lv->read_ahead);
|
||||
}
|
||||
|
||||
if (lv->major >= 0)
|
||||
outf(f, "major = %d", lv->major);
|
||||
if (lv->minor >= 0)
|
||||
|
@ -523,9 +523,21 @@ static int _read_lvnames(struct format_instance *fid __attribute((unused)),
|
||||
}
|
||||
}
|
||||
|
||||
/* read_ahead defaults to 0 */
|
||||
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
|
||||
lv->read_ahead = 0;
|
||||
/* If not present, choice of auto or none is configurable */
|
||||
lv->read_ahead = vg->cmd->default_settings.read_ahead;
|
||||
else {
|
||||
switch (lv->read_ahead) {
|
||||
case 0:
|
||||
lv->read_ahead = DM_READ_AHEAD_AUTO;
|
||||
break;
|
||||
case -1:
|
||||
lv->read_ahead = DM_READ_AHEAD_NONE;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
|
@ -1705,7 +1705,7 @@ struct logical_volume *lv_create_empty(const char *name,
|
||||
|
||||
lv->status = status;
|
||||
lv->alloc = alloc;
|
||||
lv->read_ahead = 0;
|
||||
lv->read_ahead = vg->cmd->default_settings.read_ahead;
|
||||
lv->major = -1;
|
||||
lv->minor = -1;
|
||||
lv->size = UINT64_C(0);
|
||||
|
@ -82,6 +82,7 @@ struct pv_segment;
|
||||
//#define FMT_PRECOMMIT 0x00000040U /* Supports pre-commit? */
|
||||
#define FMT_RESIZE_PV 0x00000080U /* Supports pvresize? */
|
||||
#define FMT_UNLIMITED_STRIPESIZE 0x00000100U /* Unlimited stripe size? */
|
||||
#define FMT_RESTRICTED_READAHEAD 0x00000200U /* Readahead restricted to 2-120? */
|
||||
|
||||
/* LVM2 external library flags */
|
||||
#define CORRECT_INCONSISTENT 0x00000001U /* Correct inconsistent metadata */
|
||||
|
@ -23,8 +23,10 @@ FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name", "Name. LVs created for in
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr", "Various attributes - see man page.")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major", "Persistent major number or -1 if not persistent.")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor", "Persistent minor number or -1 if not persistent.")
|
||||
FIELD(LVS, lv, NUM, "Rahead", lvid, 6, lvreadahead, "lv_read_ahead", "Read ahead setting in current units.")
|
||||
FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major", "Currently assigned major number or -1 if LV is not active.")
|
||||
FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor", "Currently assigned minor number or -1 if LV is not active.")
|
||||
FIELD(LVS, lv, NUM, "KRahead", lvid, 7, lvkreadahead, "lv_kernel_read_ahead", "Currently-in-use read ahead setting in current units.")
|
||||
FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size", "Size of LV in current units.")
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count", "Number of segments in LV.")
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin", "For snapshots, the origin device of this LV")
|
||||
|
@ -59,6 +59,8 @@ static char _alloc_policy_char(alloc_policy_t alloc)
|
||||
}
|
||||
}
|
||||
|
||||
static const uint64_t _minusone = UINT64_C(-1);
|
||||
|
||||
/*
|
||||
* Data-munging functions to prepare each data type for display and sorting
|
||||
*/
|
||||
@ -224,12 +226,11 @@ static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute((u
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lvinfo info;
|
||||
uint64_t minusone = UINT64_C(-1);
|
||||
|
||||
if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
|
||||
return dm_report_field_int(rh, field, &info.major);
|
||||
|
||||
return dm_report_field_uint64(rh, field, &minusone);
|
||||
return dm_report_field_uint64(rh, field, &_minusone);
|
||||
}
|
||||
|
||||
static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
|
||||
@ -238,12 +239,11 @@ static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((u
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lvinfo info;
|
||||
uint64_t minusone = UINT64_C(-1);
|
||||
|
||||
if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
|
||||
return dm_report_field_int(rh, field, &info.minor);
|
||||
|
||||
return dm_report_field_uint64(rh, field, &minusone);
|
||||
return dm_report_field_uint64(rh, field, &_minusone);
|
||||
}
|
||||
|
||||
static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
|
||||
@ -561,6 +561,32 @@ static int _size64_disp(struct dm_report *rh __attribute((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute((unused)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
uint64_t size;
|
||||
|
||||
if (lv->read_ahead == DM_READ_AHEAD_AUTO) {
|
||||
dm_report_field_set_value(field, "auto", &_minusone);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size = (uint64_t) lv->read_ahead;
|
||||
|
||||
return _size64_disp(rh, mem, field, &size, private);
|
||||
}
|
||||
|
||||
static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data,
|
||||
void *private __attribute((unused)))
|
||||
{
|
||||
// FIXME after dm support is added
|
||||
return dm_report_field_uint64(rh, field, &_minusone);
|
||||
}
|
||||
|
||||
static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
|
@ -14,7 +14,7 @@ lvchange \- change attributes of a logical volume
|
||||
[\-\-monitor {y|n}]
|
||||
[\-M/\-\-persistent y/n] [\-\-minor minor]
|
||||
[\-P/\-\-partial]
|
||||
[\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
|
||||
[\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors|auto|none]
|
||||
[\-\-refresh]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
|
||||
@ -72,9 +72,14 @@ Set to y to make the minor number specified persistent.
|
||||
.I \-p, \-\-permission r/w
|
||||
Change access permission to read-only or read/write.
|
||||
.TP
|
||||
.I \-r, \-\-readahead ReadAheadSectors
|
||||
Change read ahead sector count per logical between 2 and 120.
|
||||
For compatability with LVM1 only. Ignored by LVM2.
|
||||
.I \-r, \-\-readahead ReadAheadSectors|auto|none
|
||||
Set read ahead sector count of this logical volume.
|
||||
For volume groups with metadata in lvm1 format, this must
|
||||
be a value between 2 and 120.
|
||||
The default value is "auto" which allows the kernel to choose
|
||||
a suitable value automatically.
|
||||
"None" is equivalent to specifying zero.
|
||||
N.B. This setting is currently disregarded and "auto" is always used.
|
||||
.TP
|
||||
.I \-\-refresh
|
||||
If the logical volume is active, reload its metadata.
|
||||
|
@ -14,7 +14,7 @@ lvcreate \- create a logical volume in an existing volume group
|
||||
[\-m/\-\-mirrors Mirrors [\-\-nosync] [\-\-mirrorlog {disk|log}] [\-\-corelog]
|
||||
[\-R/\-\-regionsize MirrorLogRegionSize]]
|
||||
[\-n/\-\-name LogicalVolumeName]
|
||||
[\-p/\-\-permission r/rw] [\-r/\-\-readahead ReadAheadSectors]
|
||||
[\-p/\-\-permission r/rw] [\-r/\-\-readahead ReadAheadSectors|auto|none]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] [\-Z/\-\-zero y/n]
|
||||
VolumeGroupName [PhysicalVolumePath...]
|
||||
@ -118,9 +118,14 @@ Set access permissions to read only or read and write.
|
||||
.br
|
||||
Default is read and write.
|
||||
.TP
|
||||
.I \-r, \-\-readahead ReadAheadSectors
|
||||
Set read ahead sector count of this logical volume to a value between 2 and 120.
|
||||
Ignored by device-mapper.
|
||||
.I \-r, \-\-readahead ReadAheadSectors|auto|none
|
||||
Set read ahead sector count of this logical volume.
|
||||
For volume groups with metadata in lvm1 format, this must
|
||||
be a value between 2 and 120.
|
||||
The default value is "auto" which allows the kernel to choose
|
||||
a suitable value automatically.
|
||||
"None" is equivalent to specifying zero.
|
||||
N.B. This setting is currently disregarded and "auto" is always used.
|
||||
.TP
|
||||
.I \-R, \-\-regionsize MirrorLogRegionSize
|
||||
A mirror is divided into regions of this size (in MB), and the mirror log
|
||||
|
@ -306,6 +306,11 @@ such devices.
|
||||
\fBmirror_region_size\fP \(em Unit size in KB for copy operations
|
||||
when mirroring.
|
||||
.IP
|
||||
\fBreadahead\fP \(em Used when there is no readahead value stored
|
||||
in the volume group metadata. Set to \fBnone\fP to disable
|
||||
readahead in these circumstances or \fBauto\fP to use the default
|
||||
value chosen by the kernel.
|
||||
.IP
|
||||
\fBreserved_memory\fP, \fBreserved_stack\fP \(em How many KB to reserve
|
||||
for LVM2 to use while logical volumes are suspended. If insufficient
|
||||
memory is reserved before suspension, there is a risk of machine deadlock.
|
||||
|
@ -107,7 +107,7 @@ arg(permission_ARG, 'p', "permission", permission_arg, 0)
|
||||
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0)
|
||||
arg(partial_ARG, 'P', "partial", NULL, 0)
|
||||
arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0)
|
||||
arg(readahead_ARG, 'r', "readahead", int_arg, 0)
|
||||
arg(readahead_ARG, 'r', "readahead", readahead_arg, 0)
|
||||
arg(resizefs_ARG, 'r', "resizefs", NULL, 0)
|
||||
arg(reset_ARG, 'R', "reset", NULL, 0)
|
||||
arg(regionsize_ARG, 'R', "regionsize", size_mb_arg, 0)
|
||||
|
@ -71,7 +71,7 @@ xx(lvchange,
|
||||
"\t[-M|--persistent y|n] [--major major] [--minor minor]\n"
|
||||
"\t[-P|--partial] " "\n"
|
||||
"\t[-p|--permission r|rw]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors|auto|none]\n"
|
||||
"\t[--refresh]\n"
|
||||
"\t[--resync]\n"
|
||||
"\t[-t|--test]\n"
|
||||
@ -126,7 +126,7 @@ xx(lvcreate,
|
||||
"\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core}|--corelog}]]\n"
|
||||
"\t[-n|--name LogicalVolumeName]\n"
|
||||
"\t[-p|--permission {r|rw}]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors|auto|none]\n"
|
||||
"\t[-R|--regionsize MirrorLogRegionSize]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[--type VolumeType]\n"
|
||||
@ -149,7 +149,7 @@ xx(lvcreate,
|
||||
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
|
||||
"\t[-n|--name LogicalVolumeName]\n"
|
||||
"\t[-p|--permission {r|rw}]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors|auto|none]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[--version]\n"
|
||||
|
@ -375,12 +375,12 @@ static int lvchange_readahead(struct cmd_context *cmd,
|
||||
|
||||
read_ahead = arg_uint_value(cmd, readahead_ARG, 0);
|
||||
|
||||
/******* FIXME Ranges?
|
||||
if (read_ahead < LVM_MIN_READ_AHEAD || read_ahead > LVM_MAX_READ_AHEAD) {
|
||||
log_error("read ahead sector argument is invalid");
|
||||
if (read_ahead != DM_READ_AHEAD_AUTO &&
|
||||
(lv->vg->fid->fmt->features & FMT_RESTRICTED_READAHEAD) &&
|
||||
(read_ahead < 2 || read_ahead > 120)) {
|
||||
log_error("Metadata only supports readahead values between 2 and 120.");
|
||||
return 0;
|
||||
}
|
||||
********/
|
||||
|
||||
if (lv->read_ahead == read_ahead) {
|
||||
log_error("Read ahead is already %u for \"%s\"",
|
||||
|
@ -548,6 +548,13 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
|
||||
(vg->fid->fmt->features & FMT_RESTRICTED_READAHEAD) &&
|
||||
(lp->read_ahead < 2 || lp->read_ahead > 120)) {
|
||||
log_error("Metadata only supports readahead values between 2 and 120.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the pv list.
|
||||
*/
|
||||
|
@ -372,6 +372,27 @@ int segtype_arg(struct cmd_context *cmd, struct arg *a)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Positive integer, zero or "auto".
|
||||
*/
|
||||
int readahead_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
|
||||
{
|
||||
if (int_arg(cmd, a))
|
||||
return 1;
|
||||
|
||||
if (!strcasecmp(a->value, "auto")) {
|
||||
a->ui_value = DM_READ_AHEAD_AUTO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcasecmp(a->value, "none")) {
|
||||
a->ui_value = DM_READ_AHEAD_NONE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __alloc(int size)
|
||||
{
|
||||
if (!(_cmdline.commands = dm_realloc(_cmdline.commands, sizeof(*_cmdline.commands) * size))) {
|
||||
|
@ -147,7 +147,7 @@ int metadatatype_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int units_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int segtype_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int alloc_arg(struct cmd_context *cmd, struct arg *a);
|
||||
|
||||
int readahead_arg(struct cmd_context *cmd, struct arg *a);
|
||||
|
||||
/* we use the enums to access the switches */
|
||||
unsigned int arg_count(const struct cmd_context *cmd, int a);
|
||||
|
Loading…
x
Reference in New Issue
Block a user