/*-
* Copyright (c) 2023 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Theodore Preduta.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
if (mfd->mfd_seals & F_SEAL_GROW) {
if (*offp >= mfd->mfd_size) {
error = EPERM;
goto leave;
}
/* Truncate the write to fit in mfd_size */
if (*offp + uio->uio_resid >= mfd->mfd_size)
todo = mfd->mfd_size - *offp;
} else if (*offp + uio->uio_resid >= mfd->mfd_size) {
/* Grow to accommodate the write request. */
error = memfd_truncate_locked(fp, *offp + uio->uio_resid);
if (error != 0)
goto leave;
}
error = ubc_uiomove(mfd->mfd_uobj, uio, todo, UVM_ADV_SEQUENTIAL,
UBC_WRITE|UBC_PARTIALOK);
if (flags & FOF_UPDATE_OFFSET)
*offp = uio->uio_offset;
getnanotime(&mfd->mfd_mtime);
leave:
mutex_exit(&fp->f_lock);
return error;
}
static int
memfd_ioctl(file_t *fp, u_long cmd, void *data)
{
return EINVAL;
}
static int
memfd_fcntl(file_t *fp, u_int cmd, void *data)
{
struct memfd *mfd = fp->f_memfd;
int error = 0;
switch (cmd) {
case F_GETPATH:
strncpy(data, mfd->mfd_name, MAXPATHLEN);
return 0;
/*
* Can only add F_SEAL_WRITE if there are no currently
* open mmaps.
*
* XXX should only disallow if there are no currently
* open mmaps with PROT_WRITE.
*/
if ((mfd->mfd_seals & F_SEAL_WRITE) == 0 &&
(*(int *)data & F_SEAL_WRITE) != 0 &&
mfd->mfd_uobj->uo_refs > 1)
{
error = EBUSY;
goto leave_add_seals;
}
static int
memfd_close(file_t *fp)
{
struct memfd *mfd = fp->f_memfd;
uao_detach(mfd->mfd_uobj);
kmem_free(mfd, sizeof(*mfd));
fp->f_memfd = NULL;
return 0;
}
static int
memfd_mmap(file_t *fp, off_t *offp, size_t size, int prot, int *flagsp,
int *advicep, struct uvm_object **uobjp, int *maxprotp)
{
struct memfd *mfd = fp->f_memfd;
int error = 0;