mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 00:17:44 +00:00
34bb61f9dd
The problem is that klists claim to provide semantics for safe traversal of lists which are being modified. The failure case is when traversal of a list causes element removal (a fairly common case). The issue is that although the list node is refcounted, if it is embedded in an object (which is universally the case), then the object will be freed regardless of the klist refcount leading to slab corruption because the klist iterator refers to the prior element to get the next. The solution is to make the klist take and release references to the embedding object meaning that the embedding object won't be released until the list relinquishes the reference to it. (akpm: fast-track this because it's needed for the 2.6.13 scsi merge) Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
61 lines
1.4 KiB
C
61 lines
1.4 KiB
C
/*
|
|
* klist.h - Some generic list helpers, extending struct list_head a bit.
|
|
*
|
|
* Implementations are found in lib/klist.c
|
|
*
|
|
*
|
|
* Copyright (C) 2005 Patrick Mochel
|
|
*
|
|
* This file is rleased under the GPL v2.
|
|
*/
|
|
|
|
#ifndef _LINUX_KLIST_H
|
|
#define _LINUX_KLIST_H
|
|
|
|
#include <linux/spinlock.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/kref.h>
|
|
#include <linux/list.h>
|
|
|
|
struct klist_node;
|
|
struct klist {
|
|
spinlock_t k_lock;
|
|
struct list_head k_list;
|
|
void (*get)(struct klist_node *);
|
|
void (*put)(struct klist_node *);
|
|
};
|
|
|
|
|
|
extern void klist_init(struct klist * k, void (*get)(struct klist_node *),
|
|
void (*put)(struct klist_node *));
|
|
|
|
struct klist_node {
|
|
struct klist * n_klist;
|
|
struct list_head n_node;
|
|
struct kref n_ref;
|
|
struct completion n_removed;
|
|
};
|
|
|
|
extern void klist_add_tail(struct klist_node * n, struct klist * k);
|
|
extern void klist_add_head(struct klist_node * n, struct klist * k);
|
|
|
|
extern void klist_del(struct klist_node * n);
|
|
extern void klist_remove(struct klist_node * n);
|
|
|
|
extern int klist_node_attached(struct klist_node * n);
|
|
|
|
|
|
struct klist_iter {
|
|
struct klist * i_klist;
|
|
struct list_head * i_head;
|
|
struct klist_node * i_cur;
|
|
};
|
|
|
|
|
|
extern void klist_iter_init(struct klist * k, struct klist_iter * i);
|
|
extern void klist_iter_init_node(struct klist * k, struct klist_iter * i,
|
|
struct klist_node * n);
|
|
extern void klist_iter_exit(struct klist_iter * i);
|
|
extern struct klist_node * klist_next(struct klist_iter * i);
|
|
|
|
#endif
|