1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2014-2019, Intel Corporation */
5 * create.c -- pmempool create command source file
13 #include <sys/types.h>
15 #include <sys/statvfs.h>
26 #include "libpmemblk.h"
27 #include "libpmemlog.h"
28 #include "libpmempool.h"
30 #define DEFAULT_MODE 0664
32 * pmempool_create -- context and args for create command
34 struct pmempool_create
{
41 struct pmem_pool_params params
;
42 struct pmem_pool_params inherit_params
;
55 * pmempool_create_default -- default args for create command
57 static const struct pmempool_create pmempool_create_default
= {
61 .inherit_fname
= NULL
,
66 .write_btt_layout
= 0,
71 .type
= PMEM_POOL_TYPE_UNKNOWN
,
78 * help_str -- string for help message
80 static const char * const help_str
=
81 "Create pmem pool of specified size, type and name\n"
84 " -s, --size <size> size of pool\n"
85 " -M, --max-size use maximum available space on file system\n"
86 " -m, --mode <octal> set permissions to <octal> (the default is 0664)\n"
87 " -i, --inherit <file> take required parameters from specified pool file\n"
88 " -b, --clear-bad-blocks clear bad blocks in existing files\n"
89 " -f, --force remove the pool first\n"
90 " -v, --verbose increase verbosity level\n"
91 " -h, --help display this help and exit\n"
93 "Options for PMEMBLK:\n"
94 " -w, --write-layout force writing the BTT layout\n"
96 "Options for PMEMOBJ:\n"
97 " -l, --layout <name> layout name stored in pool's header\n"
99 "For complete documentation see %s-create(1) manual page.\n"
103 * long_options -- command line options
105 static const struct option long_options
[] = {
106 {"size", required_argument
, NULL
, 's' | OPT_ALL
},
107 {"verbose", no_argument
, NULL
, 'v' | OPT_ALL
},
108 {"help", no_argument
, NULL
, 'h' | OPT_ALL
},
109 {"max-size", no_argument
, NULL
, 'M' | OPT_ALL
},
110 {"inherit", required_argument
, NULL
, 'i' | OPT_ALL
},
111 {"mode", required_argument
, NULL
, 'm' | OPT_ALL
},
112 {"write-layout", no_argument
, NULL
, 'w' | OPT_BLK
},
113 {"layout", required_argument
, NULL
, 'l' | OPT_OBJ
},
114 {"force", no_argument
, NULL
, 'f' | OPT_ALL
},
115 {"clear-bad-blocks", no_argument
, NULL
, 'b' | OPT_ALL
},
120 * print_usage -- print application usage short description
123 print_usage(const char *appname
)
125 printf("Usage: %s create [<args>] <blk|log|obj> [<bsize>] <file>\n",
130 * print_version -- print version string
133 print_version(const char *appname
)
135 printf("%s %s\n", appname
, SRCVERSION
);
139 * pmempool_create_help -- print help message for create command
142 pmempool_create_help(const char *appname
)
144 print_usage(appname
);
145 print_version(appname
);
146 printf(help_str
, appname
);
150 * pmempool_create_obj -- create pmem obj pool
153 pmempool_create_obj(struct pmempool_create
*pcp
)
155 PMEMobjpool
*pop
= pmemobj_create(pcp
->fname
, pcp
->layout
,
156 pcp
->params
.size
, pcp
->params
.mode
);
158 outv_err("'%s' -- %s\n", pcp
->fname
, pmemobj_errormsg());
168 * pmempool_create_blk -- create pmem blk pool
171 pmempool_create_blk(struct pmempool_create
*pcp
)
173 ASSERTne(pcp
->params
.blk
.bsize
, 0);
177 PMEMblkpool
*pbp
= pmemblk_create(pcp
->fname
, pcp
->params
.blk
.bsize
,
178 pcp
->params
.size
, pcp
->params
.mode
);
180 outv_err("'%s' -- %s\n", pcp
->fname
, pmemblk_errormsg());
184 if (pcp
->write_btt_layout
) {
185 outv(1, "Writing BTT layout using block %d.\n",
186 pcp
->write_btt_layout
);
188 if (pmemblk_set_error(pbp
, 0) || pmemblk_set_zero(pbp
, 0)) {
189 outv_err("writing BTT layout to block 0 failed\n");
200 * pmempool_create_log -- create pmem log pool
203 pmempool_create_log(struct pmempool_create
*pcp
)
205 PMEMlogpool
*plp
= pmemlog_create(pcp
->fname
,
206 pcp
->params
.size
, pcp
->params
.mode
);
209 outv_err("'%s' -- %s\n", pcp
->fname
, pmemlog_errormsg());
219 * pmempool_get_max_size -- return maximum allowed size of file
223 pmempool_get_max_size(const char *fname
, uint64_t *sizep
)
227 char *name
= strdup(fname
);
232 char *dir
= dirname(name
);
234 if (statvfs(dir
, &buf
))
237 *sizep
= buf
.f_bsize
* buf
.f_bavail
;
245 pmempool_get_max_size(const char *fname
, uint64_t *sizep
)
248 ULARGE_INTEGER freespace
;
249 char *name
= strdup(fname
);
254 char *dir
= dirname(name
);
255 wchar_t *str
= util_toUTF16(dir
);
260 if (GetDiskFreeSpaceExW(str
, &freespace
, NULL
, NULL
) == 0)
263 *sizep
= freespace
.QuadPart
;
273 * print_pool_params -- print some parameters of a pool
276 print_pool_params(struct pmem_pool_params
*params
)
278 outv(1, "\ttype : %s\n", out_get_pool_type_str(params
->type
));
279 outv(1, "\tsize : %s\n", out_get_size_str(params
->size
, 2));
280 outv(1, "\tmode : 0%o\n", params
->mode
);
281 switch (params
->type
) {
282 case PMEM_POOL_TYPE_BLK
:
283 outv(1, "\tbsize : %s\n",
284 out_get_size_str(params
->blk
.bsize
, 0));
286 case PMEM_POOL_TYPE_OBJ
:
287 outv(1, "\tlayout: '%s'\n", params
->obj
.layout
);
295 * inherit_pool_params -- inherit pool parameters from specified file
298 inherit_pool_params(struct pmempool_create
*pcp
)
300 outv(1, "Parsing pool: '%s'\n", pcp
->inherit_fname
);
303 * If no type string passed, --inherit option must be passed
304 * so parse file and get required parameters.
306 if (pmem_pool_parse_params(pcp
->inherit_fname
,
307 &pcp
->inherit_params
, 1)) {
309 perror(pcp
->inherit_fname
);
311 outv_err("%s: cannot determine type of pool\n",
316 if (PMEM_POOL_TYPE_UNKNOWN
== pcp
->inherit_params
.type
) {
317 outv_err("'%s' -- unknown pool type\n",
322 print_pool_params(&pcp
->inherit_params
);
328 * pmempool_create_parse_args -- parse command line args
331 pmempool_create_parse_args(struct pmempool_create
*pcp
, const char *appname
,
332 int argc
, char *argv
[], struct options
*opts
)
335 while ((opt
= util_options_getopt(argc
, argv
, "vhi:s:Mm:l:wfb",
342 pmempool_create_help(appname
);
345 pcp
->str_size
= optarg
;
346 ret
= util_parse_size(optarg
,
347 (size_t *)&pcp
->params
.size
);
348 if (ret
|| pcp
->params
.size
== 0) {
349 outv_err("invalid size value specified '%s'\n",
358 pcp
->str_mode
= optarg
;
359 if (util_parse_mode(optarg
, &pcp
->params
.mode
)) {
360 outv_err("invalid mode value specified '%s'\n",
366 pcp
->inherit_fname
= optarg
;
369 pcp
->write_btt_layout
= 1;
372 pcp
->layout
= optarg
;
378 pcp
->clearbadblocks
= 1;
381 print_usage(appname
);
386 /* check for <type>, <bsize> and <file> strings */
387 if (optind
+ 2 < argc
) {
388 pcp
->str_type
= argv
[optind
];
389 pcp
->str_bsize
= argv
[optind
+ 1];
390 pcp
->fname
= argv
[optind
+ 2];
391 } else if (optind
+ 1 < argc
) {
392 pcp
->str_type
= argv
[optind
];
393 pcp
->fname
= argv
[optind
+ 1];
394 } else if (optind
< argc
) {
395 pcp
->fname
= argv
[optind
];
396 pcp
->str_type
= NULL
;
398 print_usage(appname
);
406 allocate_max_size_available_file(const char *name_of_file
, mode_t mode
,
409 int fd
= os_open(name_of_file
, O_CREAT
| O_EXCL
| O_RDWR
, mode
);
411 outv_err("!open '%s' failed", name_of_file
);
416 os_off_t length
= max_size
- (max_size
% (os_off_t
)Pagesize
);
419 ret
= os_posix_fallocate(fd
, offset
, length
);
422 else if (ret
!= ENOSPC
) {
424 if (os_unlink(name_of_file
) == -1)
425 outv_err("!unlink '%s' failed", name_of_file
);
427 outv_err("!space allocation for '%s' failed",
433 length
-= (length
% (os_off_t
)Pagesize
);
434 } while (length
> (os_off_t
)Pagesize
);
442 * pmempool_create_func -- main function for create command
445 pmempool_create_func(const char *appname
, int argc
, char *argv
[])
448 struct pmempool_create pc
= pmempool_create_default
;
449 pc
.opts
= util_options_alloc(long_options
, sizeof(long_options
) /
450 sizeof(long_options
[0]), NULL
);
452 /* parse command line arguments */
453 ret
= pmempool_create_parse_args(&pc
, appname
, argc
, argv
, pc
.opts
);
457 /* set verbosity level */
458 out_set_vlevel(pc
.verbose
);
462 int exists
= util_file_exists(pc
.fname
);
467 int is_poolset
= util_is_poolset_file(pc
.fname
) == 1;
469 if (pc
.inherit_fname
) {
470 if (inherit_pool_params(&pc
)) {
471 outv_err("parsing pool '%s' failed\n",
478 * Parse pool type and other parameters if --inherit option
479 * passed. It is possible to either pass --inherit option
480 * or pool type string in command line arguments. This is
484 /* parse pool type string if passed in command line arguments */
485 pc
.params
.type
= pmem_pool_type_parse_str(pc
.str_type
);
486 if (PMEM_POOL_TYPE_UNKNOWN
== pc
.params
.type
) {
487 outv_err("'%s' -- unknown pool type\n", pc
.str_type
);
491 if (PMEM_POOL_TYPE_BLK
== pc
.params
.type
) {
492 if (pc
.str_bsize
== NULL
) {
493 outv_err("blk pool requires <bsize> "
497 if (util_parse_size(pc
.str_bsize
,
498 (size_t *)&pc
.params
.blk
.bsize
)) {
499 outv_err("cannot parse '%s' as block size\n",
505 if (PMEM_POOL_TYPE_OBJ
== pc
.params
.type
&& pc
.layout
!= NULL
) {
506 size_t max_layout
= PMEMOBJ_MAX_LAYOUT
;
508 if (strlen(pc
.layout
) >= max_layout
) {
510 "Layout name is too long, maximum number of characters (including the terminating null byte) is %zu\n",
515 size_t len
= sizeof(pc
.params
.obj
.layout
);
516 strncpy(pc
.params
.obj
.layout
, pc
.layout
, len
);
517 pc
.params
.obj
.layout
[len
- 1] = '\0';
519 } else if (pc
.inherit_fname
) {
520 pc
.params
.type
= pc
.inherit_params
.type
;
522 /* neither pool type string nor --inherit options passed */
523 print_usage(appname
);
527 if (util_options_verify(pc
.opts
, pc
.params
.type
))
530 if (pc
.params
.type
!= PMEM_POOL_TYPE_BLK
&& pc
.str_bsize
!= NULL
) {
531 outv_err("invalid option specified for %s pool type"
533 out_get_pool_type_str(pc
.params
.type
));
538 if (pc
.params
.size
) {
539 outv_err("-s|--size cannot be used with "
545 outv_err("-M|--max-size cannot be used with "
551 if (pc
.params
.size
&& pc
.max_size
) {
552 outv_err("-M|--max-size option cannot be used with -s|--size"
557 if (pc
.inherit_fname
) {
558 if (!pc
.str_size
&& !pc
.max_size
)
559 pc
.params
.size
= pc
.inherit_params
.size
;
561 pc
.params
.mode
= pc
.inherit_params
.mode
;
562 switch (pc
.params
.type
) {
563 case PMEM_POOL_TYPE_BLK
:
565 pc
.params
.blk
.bsize
=
566 pc
.inherit_params
.blk
.bsize
;
568 case PMEM_POOL_TYPE_OBJ
:
570 memcpy(pc
.params
.obj
.layout
,
571 pc
.inherit_params
.obj
.layout
,
572 sizeof(pc
.params
.obj
.layout
));
574 size_t len
= sizeof(pc
.params
.obj
.layout
);
575 strncpy(pc
.params
.obj
.layout
, pc
.layout
,
577 pc
.params
.obj
.layout
[len
- 1] = '\0';
586 * If neither --size nor --inherit options passed, check
587 * for --max-size option - if not passed use minimum pool size.
589 uint64_t min_size
= pmem_pool_get_min_size(pc
.params
.type
);
590 if (pc
.params
.size
== 0) {
592 outv(1, "Maximum size option passed "
593 "- getting available space of file system.\n");
594 ret
= pmempool_get_max_size(pc
.fname
,
597 outv_err("cannot get available space of fs\n");
600 if (pc
.params
.size
== 0) {
601 outv_err("No space left on device\n");
604 outv(1, "Available space is %s\n",
605 out_get_size_str(pc
.params
.size
, 2));
606 if (allocate_max_size_available_file(pc
.fname
,
608 (os_off_t
)pc
.params
.size
))
611 * We are going to create pool based
612 * on file size instead of the pc.params.size.
617 outv(1, "No size option passed "
618 "- picking minimum pool size.\n");
619 pc
.params
.size
= min_size
;
623 if (pc
.params
.size
< min_size
) {
624 outv_err("size must be >= %lu bytes\n", min_size
);
630 pmempool_rm(pc
.fname
, PMEMPOOL_RM_FORCE
);
632 outv(1, "Creating pool: %s\n", pc
.fname
);
633 print_pool_params(&pc
.params
);
635 if (pc
.clearbadblocks
) {
636 int ret
= util_pool_clear_badblocks(pc
.fname
,
637 1 /* ignore non-existing */);
639 outv_err("'%s' -- clearing bad blocks failed\n",
645 switch (pc
.params
.type
) {
646 case PMEM_POOL_TYPE_BLK
:
647 ret
= pmempool_create_blk(&pc
);
649 case PMEM_POOL_TYPE_LOG
:
650 ret
= pmempool_create_log(&pc
);
652 case PMEM_POOL_TYPE_OBJ
:
653 ret
= pmempool_create_obj(&pc
);
661 outv_err("creating pool file failed\n");
663 util_unlink(pc
.fname
);
666 util_options_free(pc
.opts
);