mirror of
https://github.com/versity/scoutfs.git
synced 2026-01-10 13:47:27 +00:00
This adds some minor functionality to the per_task API for use by the upcoming offline waiting work. Add scoutfs_per_task_add_excl() so that a caller can tell if their task was already put on a per-task list by their caller. Make scoutfs_per_task_del() return a bool to indicate if the entry was found on a list and was in fact deleted, or not. Add scoutfs_per_task_init_entry() for initializing entries that aren't declared on the stack. Signed-off-by: Zach Brown <zab@versity.com>
112 lines
2.8 KiB
C
112 lines
2.8 KiB
C
/*
|
|
* 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);
|
|
}
|
|
|
|
/*
|
|
* Add the entry to the per-task list if the task didn't already have an
|
|
* entry on the list. Returns true if the entry was added, false if it
|
|
* wasn't.
|
|
*/
|
|
bool scoutfs_per_task_add_excl(struct scoutfs_per_task *pt,
|
|
struct scoutfs_per_task_entry *ent, void *ptr)
|
|
{
|
|
if (!scoutfs_per_task_get(pt)) {
|
|
scoutfs_per_task_add(pt, ent, ptr);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Return true if the entry was found on the list and was deleted,
|
|
* returns false if the entry wasn't present on a list.
|
|
*/
|
|
bool 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);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void scoutfs_per_task_init(struct scoutfs_per_task *pt)
|
|
{
|
|
spin_lock_init(&pt->lock);
|
|
INIT_LIST_HEAD(&pt->list);
|
|
}
|
|
|
|
void scoutfs_per_task_init_entry(struct scoutfs_per_task_entry *ent)
|
|
{
|
|
INIT_LIST_HEAD(&ent->head);
|
|
ent->task = NULL;
|
|
ent->ptr = NULL;
|
|
}
|