On Wed, 2005-05-25 at 10:33 -0500, Timothy R. Chavez wrote:
> I like your little macro.
>
Yikes, that sounds a bit dirty. My bad. ;)
:)
What I'm doing with it _is_ a bit dirty. Looks something like this.
It compiles but I haven't tested it yet or even really done a second
read through the code -- I have to be home on time today :)
It's very loosely based on Serge's patch to use a hash table for all
security objects, although I think only the module_param() line actually
survives from the original, and even that can probably go too.
--- linux-2.6.9/include/linux/audit.h~ 2005-05-25 15:56:32.000000000 +0100
+++ linux-2.6.9/include/linux/audit.h 2005-05-25 16:28:08.000000000 +0100
@@ -215,6 +215,8 @@ struct watch_transport {
/* Structure associated with inode->i_audit */
struct audit_inode_data {
+ struct audit_inode_data *next_hash;
+ struct inode *inode;
struct audit_wentry *wentry;
struct hlist_head watchlist;
rwlock_t lock;
--- linux-2.6.9/include/linux/fs.h~ 2005-05-25 14:30:18.000000000 +0100
+++ linux-2.6.9/include/linux/fs.h 2005-05-25 16:46:27.000000000 +0100
@@ -462,7 +462,6 @@ struct inode {
unsigned long i_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
- struct audit_inode_data *i_audit;
unsigned long i_state;
unsigned long dirtied_when; /* jiffies of first dirtying */
--- linux-2.6.9/fs/inode.c~ 2005-05-25 14:30:18.000000000 +0100
+++ linux-2.6.9/fs/inode.c 2005-05-25 16:47:35.000000000 +0100
@@ -135,7 +135,6 @@ static struct inode *alloc_inode(struct
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_rdev = 0;
- inode->i_audit = NULL;
inode->i_security = NULL;
inode->dirtied_when = 0;
if (audit_inode_alloc(inode) || security_inode_alloc(inode)) {
--- linux-2.6.9/kernel/auditfs.c~ 2005-05-25 15:56:32.000000000 +0100
+++ linux-2.6.9/kernel/auditfs.c 2005-05-25 16:44:10.000000000 +0100
@@ -30,8 +30,10 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/list.h>
+#include <linux/hash.h>
#include <linux/slab.h>
#include <linux/audit.h>
+#include <linux/module.h>
#include <asm/uaccess.h>
@@ -50,8 +52,32 @@ struct audit_skb_list {
size_t size;
};
-#define inode_audit_data(inode) ((inode)->i_audit)
+static struct audit_inode_data **auditfs_hash_table;
+static spinlock_t auditfs_hash_lock = SPIN_LOCK_UNLOCKED;
+static int auditfs_hash_bits;
+static int auditfs_cache_buckets = 16384;
+module_param(auditfs_cache_buckets, int, 0);
+MODULE_PARM_DESC(auditfs_cache_buckets, "Number of auditfs cache entries to allocate
(default 16384)\n");
+
+struct audit_inode_data *inode_audit_data(struct inode *inode)
+{
+ struct audit_inode_data **list;
+ int h = hash_ptr(inode, auditfs_hash_bits);
+ struct audit_inode_data *ret = NULL;
+
+ list = &auditfs_hash_table[h];
+ spin_lock(&auditfs_hash_lock);
+
+ while (*list && (unsigned long)((*list)->inode) < (unsigned long)inode)
+ list = &(*list)->next_hash;
+
+ if (*list && (*list)->inode == inode)
+ ret = *list;
+
+ spin_unlock(&auditfs_hash_lock);
+ return ret;
+}
/* Private Interface */
@@ -371,19 +397,6 @@ static inline void audit_drain_watchlist
audit_destroy_wentry(wentry);
}
-static inline struct audit_inode_data *audit_data_alloc(void)
-{
- struct audit_inode_data *data;
-
- data = kmalloc(sizeof(struct audit_inode_data), GFP_KERNEL);
- if (data) {
- data->wentry = NULL;
- INIT_HLIST_HEAD(&data->watchlist);
- data->lock = RW_LOCK_UNLOCKED;
- }
-
- return data;
-}
static inline void audit_data_free(struct audit_inode_data *data)
{
@@ -659,20 +672,58 @@ audit_receive_watch_exit:
int audit_inode_alloc(struct inode *inode)
{
- if (inode) {
- inode_audit_data(inode) = audit_data_alloc();
- if (!inode_audit_data(inode))
- return ENOMEM;
- }
+ struct audit_inode_data *data;
+ struct audit_inode_data **list;
+ int h = hash_ptr(inode, auditfs_hash_bits);
+ data = kmalloc(sizeof(struct audit_inode_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ INIT_HLIST_HEAD(&data->watchlist);
+ data->wentry = NULL;
+ data->lock = RW_LOCK_UNLOCKED;
+ data->inode = inode;
+ data->next_hash = NULL;
+
+ /* Add it to the hash table */
+ list = &auditfs_hash_table[h];
+ spin_lock(&auditfs_hash_lock);
+
+ while (*list && (unsigned long)((*list)->inode) < (unsigned long)inode)
+ list = &(*list)->next_hash;
+
+ data->next_hash = *list;
+ *list = data;
+
+ spin_unlock(&auditfs_hash_lock);
return 0;
}
void audit_inode_free(struct inode *inode)
{
- if (inode)
- audit_data_free(inode_audit_data(inode));
+ struct audit_inode_data *data = NULL;
+ int h = hash_ptr(inode, auditfs_hash_bits);
+ struct audit_inode_data **list;
+
+ if (!inode)
+ return;
+
+ spin_lock(&auditfs_hash_lock);
+ list = &auditfs_hash_table[h];
+ while (*list && (unsigned long)((*list)->inode) < (unsigned long)inode)
+ list = &(*list)->next_hash;
+
+ if (*list && (*list)->inode == inode) {
+ data = *list;
+ *list = data->next_hash;
+ }
+ spin_unlock(&auditfs_hash_lock);
+
+ if (data)
+ audit_data_free(data);
}
+
/*
* When we delete a dentry we check to see whether or not we're being
* watched. If we are watched, we have to put back our reference to
@@ -712,6 +763,25 @@ int audit_filesystem_init(void)
if (!audit_wentry_cache)
goto audit_filesystem_init_fail;
+ /* Set up hash table for inode objects */
+ auditfs_hash_bits = long_log2(auditfs_cache_buckets);
+ if (auditfs_cache_buckets != (1 << auditfs_hash_bits)) {
+ auditfs_hash_bits++;
+ auditfs_cache_buckets = 1 << auditfs_hash_bits;
+ printk(KERN_NOTICE
+ "%s: auditfs_cache_buckets set to %d (bits %d)\n",
+ __FUNCTION__, auditfs_cache_buckets, auditfs_hash_bits);
+ }
+
+ auditfs_hash_table = kmalloc(auditfs_cache_buckets * sizeof(void *), GFP_KERNEL);
+
+ if (!auditfs_hash_table) {
+ printk(KERN_NOTICE "No memory to initialize auditfs cache.\n");
+ goto audit_filesystem_init_fail;
+ }
+
+ memset(auditfs_hash_table, 0, auditfs_cache_buckets * sizeof(void *));
+
ret = 0;
goto audit_filesystem_init_exit;
--
dwmw2