Commit f7a2788c authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Calculate the size of the backing store file.

A size can be specified in absolute terms (suffix: k, m, g, t supported),
but also as a percentage of the filesystems free space (suffix '%').

If the specified size is larger than an off_t can cope, we bisect 
repeatedly until it can.

If the size exceeds the available space of the filesystem, we truncate
to 80% of the free space.

Then round down to an integral number of blocks, sized by the larger
of the filesystem blocksize and the pagesize.

This was tricker than I'd expected...



git-svn-id: http://www.varnish-cache.org/svn/trunk@175 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 2ff21d5e
......@@ -5,17 +5,222 @@
*/
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <pthread.h>
#include <sys/param.h>
#include <sys/mount.h>
#include "vcl_lang.h"
#include "libvarnish.h"
#include "cache.h"
struct smf_sc {
char *filename;
int fd;
uintmax_t filesize;
};
struct smf {
struct storage s;
};
/*--------------------------------------------------------------------*/
static void
smf_calcsize(struct smf_sc *sc, const char *size, int newfile)
{
uintmax_t l;
unsigned bs;
char suff[2];
int i;
off_t o;
struct statfs fsst;
struct stat st;
AZ(fstat(sc->fd, &st));
AZ(fstatfs(sc->fd, &fsst));
/* We use units of the larger of filesystem blocksize and pagesize */
bs = getpagesize();
if (bs < fsst.f_bsize)
bs = fsst.f_bsize;
assert(S_ISREG(st.st_mode));
i = sscanf(size, "%ju%1s", &l, suff); /* can return -1, 0, 1 or 2 */
if (i == 0) {
fprintf(stderr,
"Error: (-sfile) size \"%s\" not understood\n", size);
exit (2);
}
if (i >= 1 && l == 0) {
fprintf(stderr,
"Error: (-sfile) zero size not permitted\n");
exit (2);
}
if (i == -1 && !newfile) /* Use the existing size of the file */
l = st.st_size;
/* We must have at least one block */
if (l < bs) {
if (i == -1) {
fprintf(stderr,
"Info: (-sfile) default to 80%% size\n");
l = 80;
suff[0] = '%';
i = 2;
}
if (i == 2) {
if (suff[0] == 'k' || suff[0] == 'K')
l *= 1024UL;
else if (suff[0] == 'm' || suff[0] == 'M')
l *= 1024UL * 1024UL;
else if (suff[0] == 'g' || suff[0] == 'G')
l *= 1024UL * 1024UL * 1024UL;
else if (suff[0] == 't' || suff[0] == 'T')
l *= (uintmax_t)(1024UL * 1024UL) *
(uintmax_t)(1024UL * 1024UL);
else if (suff[0] == '%') {
l *= fsst.f_bsize * fsst.f_bavail;
l /= 100;
}
}
o = l;
if (o != l || o < 0) {
fprintf(stderr,
"Warning: size reduced to system limit (off_t)\n");
do {
l >>= 1;
o = l;
} while (o != l || o < 0);
}
if (l < st.st_size) {
AZ(ftruncate(sc->fd, l));
} else if (l - st.st_size > fsst.f_bsize * fsst.f_bavail) {
fprintf(stderr,
"Warning: size larger than filesystem free space,"
" reduced to 80%% of free space.\n");
l = (fsst.f_bsize * fsst.f_bavail * 80) / 100;
}
}
/* round down to of filesystem blocksize or pagesize */
l -= (l % bs);
assert(l >= bs);
printf("file %s size %ju bytes (%ju fs-blocks, %ju pages)\n",
sc->filename, l, l / fsst.f_bsize, l / getpagesize());
sc->filesize = l;
}
static void
smf_initfile(struct smf_sc *sc, const char *size, int newfile)
{
smf_calcsize(sc, size, newfile);
}
static void
smf_init(struct stevedore *parent, const char *spec)
{
char *size;
char *p, *q;
struct stat st;
struct smf_sc *sc;
sc = calloc(sizeof *sc, 1);
assert(sc != NULL);
/* If no size specified, use 50% of filesystem free space */
if (spec == NULL || *spec == '\0')
spec = "/tmp,50%";
if (strchr(spec, ',') == NULL)
asprintf(&p, "%s,", spec);
else
p = strdup(spec);
assert(p != NULL);
size = strchr(p, ',');
assert(size != NULL);
*size++ = '\0';
/* try to create a new file of this name */
sc->fd = open(p, O_RDWR | O_CREAT | O_EXCL, 0600);
if (sc->fd >= 0) {
sc->filename = p;
smf_initfile(sc, size, 1);
return;
}
/* it must exist then */
if (stat(p, &st)) {
fprintf(stderr,
"Error: (-sfile) \"%s\" "
"does not exist and could not be created\n", p);
exit (2);
}
/* and it should be a file or directory */
if (!(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
fprintf(stderr,
"Error: (-sfile) \"%s\" "
"is neither file nor directory\n", p);
exit (2);
}
if (S_ISREG(st.st_mode)) {
sc->fd = open(p, O_RDWR);
if (sc->fd < 0) {
fprintf(stderr,
"Error: (-sfile) \"%s\" "
"could not open (%s)\n", p, strerror(errno));
exit (2);
}
AZ(fstat(sc->fd, &st));
if (!S_ISREG(st.st_mode)) {
fprintf(stderr,
"Error: (-sfile) \"%s\" "
"was not a file after opening\n", p);
exit (2);
}
sc->filename = p;
smf_initfile(sc, size, 0);
return;
}
asprintf(&q, "%s/varnish.XXXXXX", p);
assert(q != NULL);
sc->fd = mkstemp(q);
if (sc->fd < 0) {
fprintf(stderr,
"Error: (-sfile) \"%s\" "
"mkstemp(%s) failed (%s)\n", p, q, strerror(errno));
exit (2);
}
AZ(unlink(q));
asprintf(&sc->filename, "%s (unlinked)", q);
assert(sc->filename != NULL);
free(q);
smf_initfile(sc, size, 1);
}
static struct storage *
smf_alloc(struct stevedore *st __unused, unsigned size)
{
......@@ -42,7 +247,7 @@ smf_free(struct storage *s)
struct stevedore smf_stevedore = {
"file",
NULL, /* init */
smf_init, /* init */
NULL, /* open */
smf_alloc,
smf_free
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment