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 <zab@versity.com>
This commit is contained in:
Zach Brown
2017-09-29 09:48:38 -07:00
committed by Mark Fasheh
parent 0535e249d1
commit c3e690a1ac
3 changed files with 109 additions and 2 deletions

View File

@@ -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

81
kmod/src/per_task.c Normal file
View File

@@ -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 <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#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);
}

25
kmod/src/per_task.h Normal file
View File

@@ -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