svn commit: r352747 - in head: lib/libc/sys sys/compat/freebsd32 sys/kern sys/sys tests/sys/posixshm usr.bin/truss
Konstantin Belousov
kostikbel at gmail.com
Thu Sep 26 17:53:51 UTC 2019
On Thu, Sep 26, 2019 at 03:32:28PM +0000, David Bright wrote:
> Author: dab
> Date: Thu Sep 26 15:32:28 2019
> New Revision: 352747
> URL: https://svnweb.freebsd.org/changeset/base/352747
>
> Log:
> Add an shm_rename syscall
> Modified: head/sys/kern/uipc_shm.c
> ==============================================================================
> --- head/sys/kern/uipc_shm.c Thu Sep 26 15:18:57 2019 (r352746)
> +++ head/sys/kern/uipc_shm.c Thu Sep 26 15:32:28 2019 (r352747)
> @@ -33,8 +33,9 @@
>
> /*
> * Support for shared swap-backed anonymous memory objects via
> - * shm_open(2) and shm_unlink(2). While most of the implementation is
> - * here, vm_mmap.c contains mapping logic changes.
> + * shm_open(2), shm_rename(2), and shm_unlink(2).
> + * While most of the implementation is here, vm_mmap.c contains
> + * mapping logic changes.
> *
> * posixshmcontrol(1) allows users to inspect the state of the memory
> * objects. Per-uid swap resource limit controls total amount of
> @@ -945,6 +946,158 @@ sys_shm_unlink(struct thread *td, struct shm_unlink_ar
> free(path, M_TEMP);
>
> return (error);
> +}
> +
> +int
> +sys_shm_rename(struct thread *td, struct shm_rename_args *uap)
> +{
> + char *path_from = NULL, *path_to = NULL;
> + Fnv32_t fnv_from, fnv_to;
> + struct shmfd *fd_from;
> + struct shmfd *fd_to;
> + int error;
> + int flags;
> +
> + flags = uap->flags;
> +
> + /*
> + * Make sure the user passed only valid flags.
> + * If you add a new flag, please add a new term here.
> + */
> + if ((flags & ~(
> + SHM_RENAME_NOREPLACE |
> + SHM_RENAME_EXCHANGE
> + )) != 0) {
> + error = EINVAL;
> + goto out;
> + }
> +
> + /*
> + * EXCHANGE and NOREPLACE don't quite make sense together. Let's
> + * force the user to choose one or the other.
> + */
> + if ((flags & SHM_RENAME_NOREPLACE) != 0 &&
> + (flags & SHM_RENAME_EXCHANGE) != 0) {
> + error = EINVAL;
> + goto out;
> + }
> +
> + /*
> + * Malloc zone M_SHMFD, since this path may end up freed later from
> + * M_SHMFD if we end up doing an insert.
> + */
I do not quite get the comment.
> + path_from = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK);
> + error = copyinstr(uap->path_from, path_from, MAXPATHLEN, NULL);
> + if (error)
> + goto out;
> +
> + path_to = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK);
> + error = copyinstr(uap->path_to, path_to, MAXPATHLEN, NULL);
> + if (error)
> + goto out;
> +
> + /* Rename with from/to equal is a no-op */
> + if (strncmp(path_from, path_to, MAXPATHLEN) == 0)
> + goto out;
Is this needed for correctness, or just a micro-optimization ?
We require that all shm names started with '/'. I do not see a check
for that in your code, so it seems that you allow to create such entries.
Also look at the special handling for jailed callers in kern_shm_open().
> +
> + fnv_from = fnv_32_str(path_from, FNV1_32_INIT);
> + fnv_to = fnv_32_str(path_to, FNV1_32_INIT);
> +
> + sx_xlock(&shm_dict_lock);
> +
> + fd_from = shm_lookup(path_from, fnv_from);
> + if (fd_from == NULL) {
> + sx_xunlock(&shm_dict_lock);
> + error = ENOENT;
> + goto out;
I think you can put an out_locked label just before final unlock
and jump to it instead of repeating sx_xunlock().
> + }
> +
> + fd_to = shm_lookup(path_to, fnv_to);
You added truss support, but not ktrace. I think it would be useful
to report looked up names, see the use of KTR_NAMEI tracepoints in
kern_shm_open().
> + if ((flags & SHM_RENAME_NOREPLACE) != 0 && fd_to != NULL) {
> + sx_xunlock(&shm_dict_lock);
> + error = EEXIST;
> + goto out;
> + }
> +
> + /*
> + * Unconditionally prevents shm_remove from invalidating the 'from'
> + * shm's state.
> + */
> + shm_hold(fd_from);
> + error = shm_remove(path_from, fnv_from, td->td_ucred);
> +
> + /*
> + * One of my assumptions failed if ENOENT (e.g. locking didn't
> + * protect us)
> + */
> + KASSERT(error != ENOENT, ("Our shm disappeared during shm_rename: %s",
> + path_from));
> + if (error) {
> + shm_drop(fd_from);
> + sx_xunlock(&shm_dict_lock);
> + goto out;
> + }
> +
> + /*
> + * If we are exchanging, we need to ensure the shm_remove below
> + * doesn't invalidate the dest shm's state.
> + */
> + if ((flags & SHM_RENAME_EXCHANGE) != 0 && fd_to != NULL)
> + shm_hold(fd_to);
> +
> + /*
> + * NOTE: if path_to is not already in the hash, c'est la vie;
> + * it simply means we have nothing already at path_to to unlink.
> + * That is the ENOENT case.
> + *
> + * If we somehow don't have access to unlink this guy, but
> + * did for the shm at path_from, then relink the shm to path_from
> + * and abort with EACCES.
> + *
> + * All other errors: that is weird; let's relink and abort the
> + * operation.
> + */
> + error = shm_remove(path_to, fnv_to, td->td_ucred);
> + if (error && error != ENOENT) {
> + shm_insert(path_from, fnv_from, fd_from);
> + shm_drop(fd_from);
> + /* Don't free path_from now, since the hash references it */
> + path_from = NULL;
> + sx_xunlock(&shm_dict_lock);
> + goto out;
> + }
> +
> + shm_insert(path_to, fnv_to, fd_from);
> +
> + /* Don't free path_to now, since the hash references it */
> + path_to = NULL;
> +
> + /* We kept a ref when we removed, and incremented again in insert */
> + shm_drop(fd_from);
> +#ifdef DEBUG
This is weird. Why did you put KASSERT under some custom define protection ?
> + KASSERT(fd_from->shm_refs > 0, ("Expected >0 refs; got: %d\n",
> + fd_from->shm_refs));
> +#endif
> +
> + if ((flags & SHM_RENAME_EXCHANGE) != 0 && fd_to != NULL) {
> + shm_insert(path_from, fnv_from, fd_to);
> + path_from = NULL;
> + shm_drop(fd_to);
> +#ifdef DEBUG
> + KASSERT(fd_to->shm_refs > 0, ("Expected >0 refs; got: %d\n",
> + fd_to->shm_refs));
> +#endif
> + }
> +
> + error = 0;
I do not think this assignment does anything useful.
> + sx_xunlock(&shm_dict_lock);
> +
> +out:
> + if (path_from != NULL)
You do not need the checks, calls free() unconditionally.
> + free(path_from, M_SHMFD);
> + if (path_to != NULL)
> + free(path_to, M_SHMFD);
> + return(error);
There should be space before '('.
> }
>
> int
>
> Modified: head/sys/sys/mman.h
> ==============================================================================
> --- head/sys/sys/mman.h Thu Sep 26 15:18:57 2019 (r352746)
> +++ head/sys/sys/mman.h Thu Sep 26 15:32:28 2019 (r352747)
> @@ -134,6 +134,14 @@
> #define MAP_FAILED ((void *)-1)
>
> /*
> + * Flags provided to shm_rename
> + */
> +/* Don't overwrite dest, if it exists */
> +#define SHM_RENAME_NOREPLACE (1 << 0)
> +/* Atomically swap src and dest */
> +#define SHM_RENAME_EXCHANGE (1 << 1)
You already got a note about namespace.
> +
> +/*
> * msync() flags
> */
> #define MS_SYNC 0x0000 /* msync synchronously */
> @@ -313,6 +321,7 @@ int posix_madvise(void *, size_t, int);
> int mlockall(int);
> int munlockall(void);
> int shm_open(const char *, int, mode_t);
> +int shm_rename(const char *, const char *, int);
> int shm_unlink(const char *);
> #endif
> #if __BSD_VISIBLE
More information about the svn-src-all
mailing list