From: Wang Wensheng wangwensheng4@huawei.com
We expend the structure xshm_task_block_cnt to link all the TASK that have got the BLOCK in the xshm_block structure, so we can find all the TASKs and delete theirs refcnt when delete the BLOCK.
Signed-off-by: Wang Wensheng wangwensheng4@huawei.com --- include/uapi/linux/xshmem_framework.h | 1 + lib/xshmem/xshmem_framework.c | 72 ++++++++++++++++++++++++----------- lib/xshmem/xshmem_framework.h | 2 + 3 files changed, 53 insertions(+), 22 deletions(-)
diff --git a/include/uapi/linux/xshmem_framework.h b/include/uapi/linux/xshmem_framework.h index 2ac2467..08ac069 100644 --- a/include/uapi/linux/xshmem_framework.h +++ b/include/uapi/linux/xshmem_framework.h @@ -28,6 +28,7 @@ struct xshm_block_arg { #define XSHMEM_BLOCK_ALLOC _IOW('X', 3, struct xshm_block_arg) #define XSHMEM_BLOCK_GET _IOW('X', 4, struct xshm_block_arg) #define XSHMEM_BLOCK_PUT _IOW('X', 5, struct xshm_block_arg) +#define XSHMEM_BLOCK_DELETE _IOW('X', 6, struct xshm_block_arg)
#define XSHMEM_ALGO_EMPTY -1 #define XSHMEM_ALGO_BLOCK 0 diff --git a/lib/xshmem/xshmem_framework.c b/lib/xshmem/xshmem_framework.c index 561f235..ae6899f 100644 --- a/lib/xshmem/xshmem_framework.c +++ b/lib/xshmem/xshmem_framework.c @@ -52,11 +52,20 @@ static struct hlist_head *hash_bucket(char *key, int len) }
struct xshm_task_block_cnt { - struct list_head list; - struct xshm_block *blk; int refcnt; + struct list_head node_list; /* list node in TASK node */ + struct list_head blk_list; /* list node in BLOCK */ + struct xshm_block *blk; + struct xshm_task_pool_node *node; };
+static void task_block_cnt_destroy(struct xshm_task_block_cnt *cnt) +{ + list_del(&cnt->node_list); + list_del(&cnt->blk_list); + kfree(cnt); +} + struct xshm_task_pool_node { struct list_head task_node; // list node in TASK struct list_head pool_node; // list node in POOL @@ -64,7 +73,7 @@ struct xshm_task_pool_node { struct xshm_pool *pool;
/* list_head for all BLOCKs' refcnt in the POOL allocated by the TASK */ - struct list_head block_head; + struct list_head list_head; };
struct xshm_task { @@ -125,7 +134,7 @@ static int xshmem_pool_attach(struct xshm_task *task, struct xshm_pool *xp) node->task = task; node->pool = xp; list_add_tail(&node->task_node, &task->list_head); - INIT_LIST_HEAD(&node->block_head); + INIT_LIST_HEAD(&node->list_head);
/* Do not add node to xp->list_head until all its elements initilized */ spin_lock(&xp->xp_task_spinlock); @@ -151,14 +160,14 @@ static void xshmem_task_clear_block(struct xshm_task_pool_node *node) struct xshm_task_block_cnt *cnt, *tmp;
mutex_lock(&xp->xp_block_mutex); - list_for_each_entry_safe(cnt, tmp, &node->block_head, list) { + list_for_each_entry_safe(cnt, tmp, &node->list_head, node_list) { struct xshm_block *blk = cnt->blk;
blk->refcnt -= cnt->refcnt; if (!blk->refcnt) xshmem_block_destroy(xp, blk);
- kfree(cnt); + task_block_cnt_destroy(cnt); } mutex_unlock(&xp->xp_block_mutex); } @@ -396,11 +405,14 @@ static int ioctl_xshmem_block_alloc(struct xshm_pool *xp, struct xshm_task_pool_ } else { blk->refcnt = 1; blk->offset = ret; + INIT_LIST_HEAD(&blk->list_head); list_add_tail(&blk->block_node, &xp->block_head);
cnt->refcnt = 1; cnt->blk = blk; - list_add_tail(&cnt->list, &node->block_head); + cnt->node = node; + list_add_tail(&cnt->node_list, &node->list_head); + list_add_tail(&cnt->blk_list, &blk->list_head); } mutex_unlock(&xp->xp_block_mutex);
@@ -412,8 +424,8 @@ find_task_block_cnt(struct xshm_task_pool_node *node, struct xshm_block *blk) { struct xshm_task_block_cnt *cnt;
- list_for_each_entry(cnt, &node->block_head, list) - if (cnt->blk == blk) + list_for_each_entry(cnt, &blk->list_head, blk_list) + if (cnt->node == node) return cnt;
return NULL; @@ -440,7 +452,10 @@ static int ioctl_xshmem_block_get(struct xshm_pool *xp, struct xshm_task_pool_no
cnt->refcnt = 1; cnt->blk = blk; - list_add_tail(&cnt->list, &node->block_head); + cnt->node = node; + + list_add_tail(&cnt->node_list, &node->list_head); + list_add_tail(&cnt->blk_list, &blk->list_head); } else cnt->refcnt++;
@@ -454,7 +469,8 @@ static int ioctl_xshmem_block_get(struct xshm_pool *xp, struct xshm_task_pool_no return ret; }
-static int ioctl_xshmem_block_put(struct xshm_pool *xp, struct xshm_task_pool_node *node, u32 offset) +static int ioctl_xshmem_block_put(struct xshm_pool *xp, struct xshm_task_pool_node *node, + u32 offset, bool force_del) { int ret = 0; struct xshm_block *blk; @@ -462,7 +478,7 @@ static int ioctl_xshmem_block_put(struct xshm_pool *xp, struct xshm_task_pool_no mutex_lock(&xp->xp_block_mutex); blk = xshmem_find_block(xp, offset); if (blk) { - struct xshm_task_block_cnt *cnt; + struct xshm_task_block_cnt *cnt, *tmp;
cnt = find_task_block_cnt(node, blk); if (!cnt) { @@ -471,15 +487,23 @@ static int ioctl_xshmem_block_put(struct xshm_pool *xp, struct xshm_task_pool_no return -EPERM; }
- cnt->refcnt--; - if (!cnt->refcnt) { - list_del(&cnt->list); - kfree(cnt); - } + if (force_del) { + list_for_each_entry_safe(cnt, tmp, &blk->list_head, blk_list) { + blk->refcnt -= cnt->refcnt; + task_block_cnt_destroy(cnt); + }
- blk->refcnt--; - if (!blk->refcnt) + WARN(blk->refcnt, "refcnt for BLOCK broken\n"); xshmem_block_destroy(xp, blk); + } else { + cnt->refcnt--; + if (!cnt->refcnt) + task_block_cnt_destroy(cnt); + + blk->refcnt--; + if (!blk->refcnt) + xshmem_block_destroy(xp, blk); + } } else { pr_err("free unalloced block\n"); ret = -ENODEV; @@ -517,12 +541,15 @@ static int ioctl_xshmem_block_common(struct xshm_task *task, unsigned int cmd, u case XSHMEM_BLOCK_ALLOC: ret = ioctl_xshmem_block_alloc(xp, node, block_arg.size); break; - case XSHMEM_BLOCK_PUT: - ret = ioctl_xshmem_block_put(xp, node, block_arg.offset); - break; case XSHMEM_BLOCK_GET: ret = ioctl_xshmem_block_get(xp, node, block_arg.offset); break; + case XSHMEM_BLOCK_PUT: + ret = ioctl_xshmem_block_put(xp, node, block_arg.offset, false); + break; + case XSHMEM_BLOCK_DELETE: + ret = ioctl_xshmem_block_put(xp, node, block_arg.offset, true); + break; }
xshmem_pool_put(xp); @@ -546,6 +573,7 @@ static long xshmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case XSHMEM_BLOCK_ALLOC: case XSHMEM_BLOCK_PUT: case XSHMEM_BLOCK_GET: + case XSHMEM_BLOCK_DELETE: ret = ioctl_xshmem_block_common(task, cmd, arg); break; default: diff --git a/lib/xshmem/xshmem_framework.h b/lib/xshmem/xshmem_framework.h index 317547f..3624841 100644 --- a/lib/xshmem/xshmem_framework.h +++ b/lib/xshmem/xshmem_framework.h @@ -38,6 +38,8 @@ struct xshm_block { manage it properly */ struct list_head block_node; void *private; + + struct list_head list_head; };
#define ALGO_NAME_MAX 20