Whamcloud - gitweb
LU-6245 libcfs: create userland and kernel string operations
[fs/lustre-release.git] / lustre / utils / mount_utils.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, 2014, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #if HAVE_CONFIG_H
38 #  include "config.h"
39 #endif /* HAVE_CONFIG_H */
40
41 #include "mount_utils.h"
42 #include <mntent.h>
43 #include <stdio.h>
44 #include <errno.h>
45 #include <string.h>
46 #include <config.h>
47 #include <lustre_disk.h>
48 #include <lustre_ver.h>
49 #include <sys/mount.h>
50 #include <sys/stat.h>
51 #include <sys/utsname.h>
52 #include <linux/loop.h>
53 #include <dlfcn.h>
54
55 extern char *progname;
56 extern int verbose;
57
58 #define vprint(fmt, arg...) if (verbose > 0) printf(fmt, ##arg)
59 #define verrprint(fmt, arg...) if (verbose >= 0) fprintf(stderr, fmt, ##arg)
60
61 static struct module_backfs_ops *backfs_ops[LDD_MT_LAST];
62
63 void fatal(void)
64 {
65         verbose = 0;
66         fprintf(stderr, "\n%s FATAL: ", progname);
67 }
68
69 int run_command(char *cmd, int cmdsz)
70 {
71         char log[] = "/tmp/run_command_logXXXXXX";
72         int fd = -1, rc;
73
74         if ((cmdsz - strlen(cmd)) < 6) {
75                 fatal();
76                 fprintf(stderr, "Command buffer overflow: %.*s...\n",
77                         cmdsz, cmd);
78                 return ENOMEM;
79         }
80
81         if (verbose > 1) {
82                 printf("cmd: %s\n", cmd);
83         } else {
84                 if ((fd = mkstemp(log)) >= 0) {
85                         close(fd);
86                         strcat(cmd, " >");
87                         strcat(cmd, log);
88                 }
89         }
90         strcat(cmd, " 2>&1");
91
92         /* Can't use popen because we need the rv of the command */
93         rc = system(cmd);
94         if (rc && (fd >= 0)) {
95                 char buf[128];
96                 FILE *fp;
97                 fp = fopen(log, "r");
98                 if (fp) {
99                         while (fgets(buf, sizeof(buf), fp) != NULL) {
100                                 printf("   %s", buf);
101                         }
102                         fclose(fp);
103                 }
104         }
105         if (fd >= 0)
106                 remove(log);
107         return rc;
108 }
109
110 int add_param(char *buf, char *key, char *val)
111 {
112         int end = sizeof(((struct lustre_disk_data *)0)->ldd_params);
113         int start = strlen(buf);
114         int keylen = 0;
115
116         if (key)
117                 keylen = strlen(key);
118         if (start + 1 + keylen + strlen(val) >= end) {
119                 fprintf(stderr, "%s: params are too long-\n%s %s%s\n",
120                         progname, buf, key ? key : "", val);
121                 return 1;
122         }
123
124         sprintf(buf + start, " %s%s", key ? key : "", val);
125         return 0;
126 }
127
128 int get_param(char *buf, char *key, char **val)
129 {
130         int i, key_len = strlen(key);
131         char *ptr;
132
133         ptr = strstr(buf, key);
134         if (ptr) {
135                 *val = strdup(ptr + key_len);
136                 if (*val == NULL)
137                         return ENOMEM;
138
139                 for (i = 0; i < strlen(*val); i++)
140                         if (((*val)[i] == ' ') || ((*val)[i] == '\0'))
141                                 break;
142
143                 (*val)[i] = '\0';
144                 return 0;
145         }
146
147         return ENOENT;
148 }
149
150 int append_param(char *buf, char *key, char *val, char sep)
151 {
152         int key_len, i, offset, old_val_len;
153         char *ptr = NULL, str[1024];
154
155         if (key)
156                 ptr = strstr(buf, key);
157
158         /* key doesn't exist yet, so just add it */
159         if (ptr == NULL)
160                 return add_param(buf, key, val);
161
162         key_len = strlen(key);
163
164         /* Copy previous values to str */
165         for (i = 0; i < sizeof(str); ++i) {
166                 if ((ptr[i+key_len] == ' ') || (ptr[i+key_len] == '\0'))
167                         break;
168                 str[i] = ptr[i+key_len];
169         }
170         if (i == sizeof(str))
171                 return E2BIG;
172         old_val_len = i;
173
174         offset = old_val_len+key_len;
175
176         /* Move rest of buf to overwrite previous key and value */
177         for (i = 0; ptr[i+offset] != '\0'; ++i)
178                 ptr[i] = ptr[i+offset];
179
180         ptr[i] = '\0';
181
182         snprintf(str+old_val_len, sizeof(str)-old_val_len, "%c%s", sep, val);
183
184         return add_param(buf, key, str);
185 }
186
187 char *strscat(char *dst, char *src, int buflen)
188 {
189         dst[buflen - 1] = 0;
190         if (strlen(dst) + strlen(src) >= buflen) {
191                 fprintf(stderr, "string buffer overflow (max %d): '%s' + '%s'"
192                         "\n", buflen, dst, src);
193                 exit(EOVERFLOW);
194         }
195         return strcat(dst, src);
196 }
197
198 char *strscpy(char *dst, char *src, int buflen)
199 {
200         dst[0] = 0;
201         return strscat(dst, src, buflen);
202 }
203
204 int check_mtab_entry(char *spec1, char *spec2, char *mtpt, char *type)
205 {
206         FILE *fp;
207         struct mntent *mnt;
208
209         fp = setmntent(MOUNTED, "r");
210         if (fp == NULL)
211                 return 0;
212
213         while ((mnt = getmntent(fp)) != NULL) {
214                 if ((strcmp(mnt->mnt_fsname, spec1) == 0 ||
215                      strcmp(mnt->mnt_fsname, spec2) == 0) &&
216                     (mtpt == NULL || strcmp(mnt->mnt_dir, mtpt) == 0) &&
217                     (type == NULL || strcmp(mnt->mnt_type, type) == 0)) {
218                         endmntent(fp);
219                         return(EEXIST);
220                 }
221         }
222         endmntent(fp);
223
224         return 0;
225 }
226
227 #define PROC_DIR        "/proc/"
228 static int mtab_is_proc(const char *mtab)
229 {
230         char path[16];
231
232         if (readlink(mtab, path, sizeof(path)) < 0)
233                 return 0;
234
235         if (strncmp(path, PROC_DIR, strlen(PROC_DIR)))
236                 return 0;
237
238         return 1;
239 }
240
241 int update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
242                 int flags, int freq, int pass)
243 {
244         FILE *fp;
245         struct mntent mnt;
246         int rc = 0;
247
248         /* Don't update mtab if it is linked to any file in /proc direcotry.*/
249         if (mtab_is_proc(MOUNTED))
250                 return 0;
251
252         mnt.mnt_fsname = spec;
253         mnt.mnt_dir = mtpt;
254         mnt.mnt_type = type;
255         mnt.mnt_opts = opts ? opts : "";
256         mnt.mnt_freq = freq;
257         mnt.mnt_passno = pass;
258
259         fp = setmntent(MOUNTED, "a+");
260         if (fp == NULL) {
261                 fprintf(stderr, "%s: setmntent(%s): %s:",
262                         progname, MOUNTED, strerror (errno));
263                 rc = 16;
264         } else {
265                 if ((addmntent(fp, &mnt)) == 1) {
266                         fprintf(stderr, "%s: addmntent: %s:",
267                                 progname, strerror (errno));
268                         rc = 16;
269                 }
270                 endmntent(fp);
271         }
272
273         return rc;
274 }
275
276 /* Search for opt in mntlist, returning true if found.
277  */
278 static int in_mntlist(char *opt, char *mntlist)
279 {
280         char *ml, *mlp, *item, *ctx = NULL;
281
282         if (!(ml = strdup(mntlist))) {
283                 fprintf(stderr, "%s: out of memory\n", progname);
284                 exit(1);
285         }
286         mlp = ml;
287         while ((item = strtok_r(mlp, ",", &ctx))) {
288                 if (!strcmp(opt, item))
289                         break;
290                 mlp = NULL;
291         }
292         free(ml);
293         return (item != NULL);
294 }
295
296 /* Issue a message on stderr for every item in wanted_mountopts that is not
297  * present in mountopts.  The justwarn boolean toggles between error and
298  * warning message.  Return an error count.
299  */
300 int check_mountfsoptions(char *mountopts, char *wanted_mountopts,
301                          int justwarn)
302 {
303         char *ml, *mlp, *item, *ctx = NULL;
304         int errors = 0;
305
306         if (!(ml = strdup(wanted_mountopts))) {
307                 fprintf(stderr, "%s: out of memory\n", progname);
308                 exit(1);
309         }
310         mlp = ml;
311         while ((item = strtok_r(mlp, ",", &ctx))) {
312                 if (!in_mntlist(item, mountopts)) {
313                         fprintf(stderr, "%s: %s mount option `%s' is missing\n",
314                                 progname, justwarn ? "Warning: default"
315                                 : "Error: mandatory", item);
316                         errors++;
317                 }
318                 mlp = NULL;
319         }
320         free(ml);
321         return errors;
322 }
323
324 /* Trim embedded white space, leading and trailing commas from string s.
325  */
326 void trim_mountfsoptions(char *s)
327 {
328         char *p;
329
330         for (p = s; *p; ) {
331                 if (isspace(*p)) {
332                         memmove(p, p + 1, strlen(p + 1) + 1);
333                         continue;
334                 }
335                 p++;
336         }
337
338         while (s[0] == ',')
339                 memmove(&s[0], &s[1], strlen(&s[1]) + 1);
340
341         p = s + strlen(s) - 1;
342         while (p >= s && *p == ',')
343                 *p-- = '\0';
344 }
345
346 /* Setup a file in the first unused loop_device */
347 int loop_setup(struct mkfs_opts *mop)
348 {
349         char loop_base[20];
350         char l_device[64];
351         int i, ret = 0;
352
353         /* Figure out the loop device names */
354         if (!access("/dev/loop0", F_OK | R_OK) ||
355             !access("/dev/loop-control", F_OK | R_OK)) {
356                 strcpy(loop_base, "/dev/loop\0");
357         } else if (!access("/dev/loop/0", F_OK | R_OK)) {
358                 strcpy(loop_base, "/dev/loop/\0");
359         } else {
360                 fprintf(stderr, "%s: can't access loop devices\n", progname);
361                 return EACCES;
362         }
363
364         /* Find unused loop device */
365         for (i = 0; i < MAX_LOOP_DEVICES; i++) {
366                 char cmd[PATH_MAX];
367                 int cmdsz = sizeof(cmd);
368
369 #ifdef LOOP_CTL_GET_FREE
370                 ret = open("/dev/loop-control", O_RDWR);
371                 if (ret < 0) {
372                         fprintf(stderr, "%s: can't access loop control\n", progname);
373                         return EACCES;
374                 }
375                 /* find or allocate a free loop device to use */
376                 i = ioctl(ret, LOOP_CTL_GET_FREE);
377                 if (i < 0) {
378                         fprintf(stderr, "%s: access loop control error\n", progname);
379                         return EACCES;
380                 }
381                 sprintf(l_device, "%s%d", loop_base, i);
382 #else
383                 sprintf(l_device, "%s%d", loop_base, i);
384                 if (access(l_device, F_OK | R_OK))
385                         break;
386 #endif
387                 snprintf(cmd, cmdsz, "losetup %s > /dev/null 2>&1", l_device);
388                 ret = system(cmd);
389
390                 /* losetup gets 1 (ret=256) for non-set-up device */
391                 if (ret) {
392                         /* Set up a loopback device to our file */
393                         snprintf(cmd, cmdsz, "losetup %s %s", l_device,
394                                  mop->mo_device);
395                         ret = run_command(cmd, cmdsz);
396                         if (ret == 256)
397                                 /* someone else picked up this loop device
398                                  * behind our back */
399                                 continue;
400                         if (ret) {
401                                 fprintf(stderr, "%s: error %d on losetup: %s\n",
402                                         progname, ret,
403                                         ret >= 0 ? strerror(ret) : "");
404                                 return ret;
405                         }
406                         strscpy(mop->mo_loopdev, l_device,
407                                 sizeof(mop->mo_loopdev));
408                         return ret;
409                 }
410         }
411
412         fprintf(stderr, "%s: out of loop devices!\n", progname);
413         return EMFILE;
414 }
415
416 int loop_cleanup(struct mkfs_opts *mop)
417 {
418         char cmd[150];
419         int ret = 0;
420
421         if ((mop->mo_flags & MO_IS_LOOP) && *mop->mo_loopdev) {
422                 int tries;
423
424                 sprintf(cmd, "losetup -d %s", mop->mo_loopdev);
425                 for (tries = 0; tries < 3; tries++) {
426                         ret = run_command(cmd, sizeof(cmd));
427                         if (ret == 0)
428                                 break;
429                         sleep(1);
430                 }
431         }
432
433         if (ret != 0)
434                 fprintf(stderr, "cannot cleanup %s: rc = %d\n",
435                         mop->mo_loopdev, ret);
436         return ret;
437 }
438
439 int loop_format(struct mkfs_opts *mop)
440 {
441         int fd;
442
443         if (mop->mo_device_kb == 0) {
444                 fatal();
445                 fprintf(stderr, "loop device requires a --device-size= "
446                         "param\n");
447                 return EINVAL;
448         }
449
450         fd = creat(mop->mo_device, S_IRUSR|S_IWUSR);
451         if (fd < 0) {
452                 fatal();
453                 fprintf(stderr, "%s: Unable to create backing store: %s\n",
454                         progname, strerror(errno));
455                 return errno;
456         }
457
458         if (ftruncate(fd, mop->mo_device_kb * 1024) != 0) {
459                 close(fd);
460                 fatal();
461                 fprintf(stderr, "%s: Unable to truncate backing store: %s\n",
462                         progname, strerror(errno));
463                 return errno;
464         }
465
466         close(fd);
467         return 0;
468 }
469
470 #define DLSYM(prefix, sym, func)                                        \
471         do {                                                            \
472                 char _fname[64];                                        \
473                 snprintf(_fname, sizeof(_fname), "%s_%s", prefix, #func); \
474                 sym->func = (typeof(sym->func))dlsym(sym->dl_handle, _fname); \
475         } while (0)
476
477 /**
478  * Load plugin for a given mount_type from ${pkglibdir}/mount_osd_FSTYPE.so and
479  * return struct of function pointers (will be freed in unloack_backfs_module).
480  *
481  * \param[in] mount_type        Mount type to load module for.
482  * \retval Value of backfs_ops struct
483  * \retval NULL if no module exists
484  */
485 struct module_backfs_ops *load_backfs_module(enum ldd_mount_type mount_type)
486 {
487         void *handle;
488         char *error, filename[512], fsname[512], *name;
489         struct module_backfs_ops *ops;
490
491         /* This deals with duplicate ldd_mount_types resolving to same OSD layer
492          * plugin (e.g. ext3/ldiskfs/ldiskfs2 all being ldiskfs) */
493         strlcpy(fsname, mt_type(mount_type), sizeof(fsname));
494         name = fsname + sizeof("osd-") - 1;
495
496         /* change osd- to osd_ */
497         fsname[sizeof("osd-") - 2] = '_';
498
499         snprintf(filename, sizeof(filename), PLUGIN_DIR"/mount_%s.so", fsname);
500
501         handle = dlopen(filename, RTLD_LAZY);
502
503         /* Check for $LUSTRE environment variable from test-framework.
504          * This allows using locally built modules to be used.
505          */
506         if (handle == NULL) {
507                 char *dirname;
508                 dirname = getenv("LUSTRE");
509                 if (dirname) {
510                         snprintf(filename, sizeof(filename),
511                                  "%s/utils/.libs/mount_%s.so",
512                                  dirname, fsname);
513                         handle = dlopen(filename, RTLD_LAZY);
514                 }
515         }
516
517         /* Do not clutter up console with missing types */
518         if (handle == NULL)
519                 return NULL;
520
521         ops = malloc(sizeof(*ops));
522         if (ops == NULL) {
523                 dlclose(handle);
524                 return NULL;
525         }
526
527         ops->dl_handle = handle;
528         dlerror(); /* Clear any existing error */
529
530         DLSYM(name, ops, init);
531         DLSYM(name, ops, fini);
532         DLSYM(name, ops, read_ldd);
533         DLSYM(name, ops, write_ldd);
534         DLSYM(name, ops, is_lustre);
535         DLSYM(name, ops, make_lustre);
536         DLSYM(name, ops, prepare_lustre);
537         DLSYM(name, ops, tune_lustre);
538         DLSYM(name, ops, label_lustre);
539         DLSYM(name, ops, enable_quota);
540
541         error = dlerror();
542         if (error != NULL) {
543                 fatal();
544                 fprintf(stderr, "%s\n", error);
545                 dlclose(handle);
546                 free(ops);
547                 return NULL;
548         }
549         return ops;
550 }
551
552 /**
553  * Unload plugin and free backfs_ops structure. Must be called the same number
554  * of times as load_backfs_module is.
555  */
556 void unload_backfs_module(struct module_backfs_ops *ops)
557 {
558         if (ops == NULL)
559                 return;
560
561         dlclose(ops->dl_handle);
562         free(ops);
563 }
564
565 /* Return true if backfs_ops has operations for the given mount_type. */
566 int backfs_mount_type_okay(enum ldd_mount_type mount_type)
567 {
568         if (unlikely(mount_type >= LDD_MT_LAST || mount_type < 0)) {
569                 fatal();
570                 fprintf(stderr, "fs type out of range %d\n", mount_type);
571                 return 0;
572         }
573         if (backfs_ops[mount_type] == NULL) {
574                 fatal();
575                 fprintf(stderr, "unhandled fs type %d '%s'\n",
576                         mount_type, mt_str(mount_type));
577                 return 0;
578         }
579         return 1;
580 }
581
582 /* Write the server config files */
583 int osd_write_ldd(struct mkfs_opts *mop)
584 {
585         struct lustre_disk_data *ldd = &mop->mo_ldd;
586         int ret;
587
588         if (backfs_mount_type_okay(ldd->ldd_mount_type))
589                 ret = backfs_ops[ldd->ldd_mount_type]->write_ldd(mop);
590
591         else
592                 ret = EINVAL;
593
594         return ret;
595 }
596
597 /* Read the server config files */
598 int osd_read_ldd(char *dev, struct lustre_disk_data *ldd)
599 {
600         int ret;
601
602         if (backfs_mount_type_okay(ldd->ldd_mount_type))
603                 ret = backfs_ops[ldd->ldd_mount_type]->read_ldd(dev, ldd);
604
605         else
606                 ret = EINVAL;
607
608         return ret;
609 }
610
611 /* Was this device formatted for Lustre */
612 int osd_is_lustre(char *dev, unsigned *mount_type)
613 {
614         int i;
615
616         vprint("checking for existing Lustre data: ");
617
618         for (i = 0; i < LDD_MT_LAST; ++i) {
619                 if (backfs_ops[i] != NULL &&
620                     backfs_ops[i]->is_lustre(dev, mount_type)) {
621                         vprint("found\n");
622                         return 1;
623                 }
624         }
625
626         vprint("not found\n");
627         return 0;
628 }
629
630 /* Build fs according to type */
631 int osd_make_lustre(struct mkfs_opts *mop)
632 {
633         struct lustre_disk_data *ldd = &mop->mo_ldd;
634         int ret;
635
636         if (backfs_mount_type_okay(ldd->ldd_mount_type))
637                 ret = backfs_ops[ldd->ldd_mount_type]->make_lustre(mop);
638
639         else
640                 ret = EINVAL;
641
642         return ret;
643 }
644
645 int osd_prepare_lustre(struct mkfs_opts *mop,
646                 char *default_mountopts, int default_len,
647                 char *always_mountopts, int always_len)
648 {
649         struct lustre_disk_data *ldd = &mop->mo_ldd;
650         int ret;
651
652         if (backfs_mount_type_okay(ldd->ldd_mount_type))
653                 ret = backfs_ops[ldd->ldd_mount_type]->prepare_lustre(mop,
654                         default_mountopts, default_len,
655                         always_mountopts, always_len);
656
657         else
658                 ret = EINVAL;
659
660         return ret;
661 }
662
663 int osd_tune_lustre(char *dev, struct mount_opts *mop)
664 {
665         struct lustre_disk_data *ldd = &mop->mo_ldd;
666         int ret;
667
668         if (backfs_mount_type_okay(ldd->ldd_mount_type))
669                 ret = backfs_ops[ldd->ldd_mount_type]->tune_lustre(dev, mop);
670
671         else
672                 ret = EINVAL;
673
674         return ret;
675 }
676
677 int osd_label_lustre(struct mount_opts *mop)
678 {
679         struct lustre_disk_data *ldd = &mop->mo_ldd;
680         int ret;
681
682         if (backfs_mount_type_okay(ldd->ldd_mount_type))
683                 ret = backfs_ops[ldd->ldd_mount_type]->label_lustre(mop);
684
685         else
686                 ret = EINVAL;
687
688         return ret;
689 }
690
691 /* Enable quota accounting */
692 int osd_enable_quota(struct mkfs_opts *mop)
693 {
694         struct lustre_disk_data *ldd = &mop->mo_ldd;
695         int ret;
696
697         if (backfs_mount_type_okay(ldd->ldd_mount_type))
698                 ret = backfs_ops[ldd->ldd_mount_type]->enable_quota(mop);
699
700         else
701                 ret = EINVAL;
702
703         return ret;
704 }
705
706 int osd_init(void)
707 {
708         int i, ret = 0;
709
710         for (i = 0; i < LDD_MT_LAST; ++i) {
711                 backfs_ops[i] = load_backfs_module(i);
712                 if (backfs_ops[i] != NULL)
713                         ret = backfs_ops[i]->init();
714                 if (ret)
715                         break;
716         }
717
718         return ret;
719 }
720
721 void osd_fini(void)
722 {
723         int i;
724
725         for (i = 0; i < LDD_MT_LAST; ++i) {
726                 if (backfs_ops[i] != NULL) {
727                         backfs_ops[i]->fini();
728                         unload_backfs_module(backfs_ops[i]);
729                         backfs_ops[i] = NULL;
730                 }
731         }
732 }
733
734 __u64 get_device_size(char* device)
735 {
736         int ret, fd;
737         __u64 size = 0;
738
739         fd = open(device, O_RDONLY);
740         if (fd < 0) {
741                 fprintf(stderr, "%s: cannot open %s: %s\n",
742                         progname, device, strerror(errno));
743                 return 0;
744         }
745
746 #ifdef BLKGETSIZE64
747         /* size in bytes. bz5831 */
748         ret = ioctl(fd, BLKGETSIZE64, (void*)&size);
749 #else
750         {
751                 __u32 lsize = 0;
752                 /* size in blocks */
753                 ret = ioctl(fd, BLKGETSIZE, (void*)&lsize);
754                 size = (__u64)lsize * 512;
755         }
756 #endif
757         close(fd);
758         if (ret < 0) {
759                 fprintf(stderr, "%s: size ioctl failed: %s\n",
760                         progname, strerror(errno));
761                 return 0;
762         }
763
764         vprint("device size = "LPU64"MB\n", size >> 20);
765         /* return value in KB */
766         return size >> 10;
767 }
768
769 int file_create(char *path, __u64 size)
770 {
771         __u64 size_max;
772         int ret;
773         int fd;
774
775         /*
776          * Since "size" is in KB, the file offset it represents could overflow
777          * off_t.
778          */
779         size_max = (off_t)1 << (_FILE_OFFSET_BITS - 1 - 10);
780         if (size >= size_max) {
781                 fprintf(stderr, "%s: "LPU64" KB: Backing store size must be "
782                         "smaller than "LPU64" KB\n", progname, size, size_max);
783                 return EFBIG;
784         }
785
786         ret = access(path, F_OK);
787         if (ret == 0) {
788                 ret = unlink(path);
789                 if (ret != 0)
790                         return errno;
791         }
792
793         fd = creat(path, S_IRUSR|S_IWUSR);
794         if (fd < 0) {
795                 fatal();
796                 fprintf(stderr, "%s: Unable to create backing store: %s\n",
797                         progname, strerror(errno));
798                 return errno;
799         }
800
801         ret = ftruncate(fd, size * 1024);
802         close(fd);
803         if (ret != 0) {
804                 fatal();
805                 fprintf(stderr, "%s: Unable to truncate backing store: %s\n",
806                         progname, strerror(errno));
807                 return errno;
808         }
809
810         return 0;
811 }