From c3e690a1ac11786dae24ff6183ebf7c932f16523 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 29 Sep 2017 09:48:38 -0700 Subject: [PATCH] scoutfs: add per_task storage helper Add some functions for storing and using per-task storage in a list. Callers can use this to pass pointers to children in a given scope when interfaces don't allow for passing individual arguments amongst concurrent callers in the scope. Signed-off-by: Zach Brown --- kmod/src/Makefile | 5 +-- kmod/src/per_task.c | 81 +++++++++++++++++++++++++++++++++++++++++++++ kmod/src/per_task.h | 25 ++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 kmod/src/per_task.c create mode 100644 kmod/src/per_task.h diff --git a/kmod/src/Makefile b/kmod/src/Makefile index 40543c43..30997479 100644 --- a/kmod/src/Makefile +++ b/kmod/src/Makefile @@ -6,8 +6,9 @@ CFLAGS_scoutfs_trace.o = -I$(src) # define_trace.h double include scoutfs-y += alloc.o bio.o btree.o client.o compact.o counters.o data.o dir.o \ dlmglue.o file.o kvec.o inode.o ioctl.o item.o key.o lock.o \ - manifest.o msg.o options.o seg.o server.o scoutfs_trace.o sock.o \ - sort_priv.o stackglue.o super.o trans.o xattr.o + manifest.o msg.o options.o per_task.o seg.o server.o \ + scoutfs_trace.o sock.o sort_priv.o stackglue.o super.o trans.o \ + xattr.o # # The raw types aren't available in userspace headers. Make sure all diff --git a/kmod/src/per_task.c b/kmod/src/per_task.c new file mode 100644 index 00000000..24b7f412 --- /dev/null +++ b/kmod/src/per_task.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2017 Versity Software, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include +#include + +#include "per_task.h" + +/* + * There are times when we'd like to pass data from a caller to its + * callee but we're bouncing through functions and callbacks that don't + * provide per-task storage. We add a trivial little locked list that + * lets a caller store a pointer for callees. The lists are put in the + * scope of the sharing so the contention is rare and limited to real + * concurrency -- imagine, for example, concurrent file reading on an + * inode. + */ + +/* + * Return the pointer that our caller added for us on the given list. + * The expected promise is that the pointer is valid until we return to + * the caller who will remove it from the list. + */ +void *scoutfs_per_task_get(struct scoutfs_per_task *pt) +{ + const struct task_struct *task = current; + struct scoutfs_per_task_entry *ent; + void *ret = NULL; + + spin_lock(&pt->lock); + + list_for_each_entry(ent, &pt->list, head) { + if (ent->task == task){ + ret = ent->ptr; + break; + } + } + + spin_unlock(&pt->lock); + + return ret; +} + +void scoutfs_per_task_add(struct scoutfs_per_task *pt, + struct scoutfs_per_task_entry *ent, void *ptr) +{ + ent->task = current; + ent->ptr = ptr; + + spin_lock(&pt->lock); + list_add(&ent->head, &pt->list); + spin_unlock(&pt->lock); +} + +void scoutfs_per_task_del(struct scoutfs_per_task *pt, + struct scoutfs_per_task_entry *ent) +{ + BUG_ON(!list_empty(&ent->head) && ent->task != current); + + if (!list_empty(&ent->head)) { + spin_lock(&pt->lock); + list_del_init(&ent->head); + spin_unlock(&pt->lock); + } +} + +void scoutfs_per_task_init(struct scoutfs_per_task *pt) +{ + spin_lock_init(&pt->lock); + INIT_LIST_HEAD(&pt->list); +} diff --git a/kmod/src/per_task.h b/kmod/src/per_task.h new file mode 100644 index 00000000..6cad8098 --- /dev/null +++ b/kmod/src/per_task.h @@ -0,0 +1,25 @@ +#ifndef _SCOUTFS_PER_TASK_H_ +#define _SCOUTFS_PER_TASK_H_ + +struct scoutfs_per_task { + spinlock_t lock; + struct list_head list; +}; + +struct scoutfs_per_task_entry { + struct list_head head; + struct task_struct *task; + void *ptr; +}; + +#define SCOUTFS_DECLARE_PER_TASK_ENTRY(name) \ + struct scoutfs_per_task_entry name + +void *scoutfs_per_task_get(struct scoutfs_per_task *pt); +void scoutfs_per_task_add(struct scoutfs_per_task *pt, + struct scoutfs_per_task_entry *ent, void *ptr); +void scoutfs_per_task_del(struct scoutfs_per_task *pt, + struct scoutfs_per_task_entry *ent); +void scoutfs_per_task_init(struct scoutfs_per_task *pt); + +#endif