Пример #1
0
EXPORTED int mappedfile_writelock(struct mappedfile *mf)
{
    int r;
    struct stat sbuf;
    const char *lockfailaction;
    int changed = 0;

    assert(mf->lock_status == MF_UNLOCKED);
    assert(mf->fd != -1);
    assert(mf->is_rw);
    assert(!mf->dirty);

    r = lock_reopen_ex(mf->fd, mf->fname, &sbuf, &lockfailaction, &changed);
    if (r < 0) {
        syslog(LOG_ERR, "IOERROR: %s %s: %m", lockfailaction, mf->fname);
        return r;
    }
    mf->lock_status = MF_WRITELOCKED;
    gettimeofday(&mf->starttime, 0);

    if (changed) buf_free(&mf->map_buf);

    _ensure_mapped(mf, sbuf.st_size, /*update*/0);

    return 0;
}
Пример #2
0
EXPORTED int mappedfile_writelock(struct mappedfile *mf)
{
    int r;
    struct stat sbuf;
    const char *lockfailaction;

    assert(mf->lock_status == MF_UNLOCKED);
    assert(mf->fd != -1);
    assert(mf->is_rw);
    assert(!mf->dirty);

    r = lock_reopen(mf->fd, mf->fname, &sbuf, &lockfailaction);
    if (r < 0) {
	syslog(LOG_ERR, "IOERROR: %s %s: %m", lockfailaction, mf->fname);
	return r;
    }
    mf->lock_status = MF_WRITELOCKED;

    /* XXX - can we guarantee the fd isn't reused? */
    if (mf->map_ino != sbuf.st_ino) {
	buf_free(&mf->map_buf);
    }

    _ensure_mapped(mf, sbuf.st_size, /*update*/0);

    return 0;
}
Пример #3
0
/* NOTE - we don't provide any guarantees that the file isn't open multiple
 * times.  So don't do that.  It will mess with your locking no end */
EXPORTED int mappedfile_open(struct mappedfile **mfp,
                             const char *fname, int flags)
{
    struct mappedfile *mf;
    struct stat sbuf;
    int openmode = (flags & MAPPEDFILE_RW) ? O_RDWR : O_RDONLY;
    int create = (flags & MAPPEDFILE_CREATE) ? 1 : 0;
    int r;

    assert(fname);
    assert(!*mfp);

    mf = xzmalloc(sizeof(struct mappedfile));
    mf->fname = xstrdup(fname);
    mf->is_rw = (flags & MAPPEDFILE_RW) ? 1 : 0;

    mf->fd = open(mf->fname, openmode, 0644);
    if (mf->fd < 0 && errno == ENOENT) {
        if (!create || !mf->is_rw) {
            r = -errno;
            goto err;
        }
        r = cyrus_mkdir(mf->fname, 0755);
        if (r < 0) {
            syslog(LOG_ERR, "IOERROR: cyrus_mkdir %s: %m", mf->fname);
            goto err;
        }
        mf->fd = open(mf->fname, O_RDWR | O_CREAT, 0644);
    }

    if (mf->fd == -1) {
        syslog(LOG_ERR, "IOERROR: open %s: %m", mf->fname);
        r = -errno;
        goto err;
    }

    /* it's zero, but set it anyway */
    mf->lock_status = MF_UNLOCKED;
    mf->dirty = 0;

    r = fstat(mf->fd, &sbuf);
    if (r < 0) {
        syslog(LOG_ERR, "IOERROR: fstat %s: %m", mf->fname);
        goto err;
    }

    _ensure_mapped(mf, sbuf.st_size, /*update*/0);

    *mfp = mf;

    return 0;

err:
    mappedfile_close(&mf);
    return r;
}
Пример #4
0
EXPORTED int mappedfile_readlock(struct mappedfile *mf)
{
    struct stat sbuf, sbuffile;
    int newfd = -1;

    assert(mf->lock_status == MF_UNLOCKED);
    assert(mf->fd != -1);
    assert(!mf->dirty);

    for (;;) {
	if (lock_shared(mf->fd, mf->fname) < 0) {
	    syslog(LOG_ERR, "IOERROR: lock_shared %s: %m", mf->fname);
	    return -EIO;
	}

	if (fstat(mf->fd, &sbuf) == -1) {
	    syslog(LOG_ERR, "IOERROR: fstat %s: %m", mf->fname);
	    lock_unlock(mf->fd, mf->fname);
	    return -EIO;
	}

	if (stat(mf->fname, &sbuffile) == -1) {
	    syslog(LOG_ERR, "IOERROR: stat %s: %m", mf->fname);
	    lock_unlock(mf->fd, mf->fname);
	    return -EIO;
	}
	if (sbuf.st_ino == sbuffile.st_ino) break;

	newfd = open(mf->fname, O_RDWR, 0644);
	if (newfd == -1) {
	    syslog(LOG_ERR, "IOERROR: open %s: %m", mf->fname);
	    lock_unlock(mf->fd, mf->fname);
	    return -EIO;
	}

	dup2(newfd, mf->fd);
	close(newfd);
    }

    mf->lock_status = MF_READLOCKED;

    /* XXX - can we guarantee the fd isn't reused? */
    if (mf->map_ino != sbuf.st_ino) {
	buf_free(&mf->map_buf);
    }

    _ensure_mapped(mf, sbuf.st_size, /*update*/0);

    return 0;
}
Пример #5
0
EXPORTED ssize_t mappedfile_pwritev(struct mappedfile *mf,
                                    const struct iovec *iov, int nio,
                                    off_t offset)
{
    ssize_t written;
    off_t pos;

    assert(mf->is_rw);
    assert(mf->fd != -1);
    assert(iov);

    if (!nio) return 0; /* nothing to write! */

    /* XXX - memcmp and don't both writing if it matches? */

    mf->dirty++;

    /* locate the file handle */
    pos = lseek(mf->fd, offset, SEEK_SET);
    if (pos < 0) {
        syslog(LOG_ERR, "IOERROR: %s seek to %llX: %m", mf->fname,
               (long long unsigned int)offset);
        return -1;
    }

    /* write the buffer */
    written = retry_writev(mf->fd, iov, nio);
    if (written < 0) {
        size_t len = 0;
        int i;
        for (i = 0; i < nio; i++) {
            len += iov[i].iov_len;
        }
        syslog(LOG_ERR, "IOERROR: %s write %llu bytes at %llX: %m",
               mf->fname, (long long unsigned int)len,
               (long long unsigned int)offset);
        return -1;
    }

    _ensure_mapped(mf, pos+written, /*update*/1);

    return written;
}
Пример #6
0
EXPORTED int mappedfile_truncate(struct mappedfile *mf, off_t offset)
{
    int r;

    assert(mf->is_rw);
    assert(mf->fd != -1);

    mf->dirty++;

    r = ftruncate(mf->fd, offset);
    if (r < 0) {
        syslog(LOG_ERR, "IOERROR: ftruncate %s: %m", mf->fname);
        return r;
    }

    _ensure_mapped(mf, offset, /*update*/0);
    mf->was_resized = 1; /* force the fsync */

    return 0;
}
Пример #7
0
EXPORTED ssize_t mappedfile_pwrite(struct mappedfile *mf,
                                   const void *base, size_t len,
                                   off_t offset)
{
    ssize_t written;
    off_t pos;

    assert(mf->is_rw);
    assert(mf->fd != -1);
    assert(base);

    if (!len) return 0; /* nothing to write! */

    /* XXX - memcmp and don't both writing if it matches? */

    mf->dirty++;

    /* locate the file handle */
    pos = lseek(mf->fd, offset, SEEK_SET);
    if (pos < 0) {
        syslog(LOG_ERR, "IOERROR: %s seek to %llX: %m", mf->fname,
               (long long unsigned int)offset);
        return -1;
    }

    /* write the buffer */
    written = retry_write(mf->fd, base, len);
    if (written < 0) {
        syslog(LOG_ERR, "IOERROR: %s write %llu bytes at %llX: %m",
               mf->fname, (long long unsigned int)len,
               (long long unsigned int)offset);
        return -1;
    }

    _ensure_mapped(mf, pos+written, /*update*/1);

    return written;
}