summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/autofs/autofs_i.h14
-rw-r--r--fs/autofs/inode.c1
-rw-r--r--fs/autofs/root.c25
-rw-r--r--fs/autofs/waitq.c44
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/proc/array.c12
6 files changed, 80 insertions, 18 deletions
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index d3b6e484f..4183b88b1 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -12,6 +12,8 @@
/* Internal header file for autofs */
+#define DEBUG_WAITLIST 1
+
#include <linux/auto_fs.h>
/* This is the range of ioctl() numbers we claim as ours */
@@ -120,7 +122,10 @@ struct autofs_symlink {
#define END_OF_TIME ((time_t)((unsigned long)((time_t)(~0UL)) >> 1))
#endif
+#define AUTOFS_SBI_MAGIC 0x6d4a556d
+
struct autofs_sb_info {
+ u32 magic;
struct file *pipe;
pid_t oz_pgrp;
int catatonic;
@@ -137,6 +142,15 @@ static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
return sbi->catatonic || current->pgrp == sbi->oz_pgrp;
}
+/* Debug the mysteriously disappearing wait list */
+
+#ifdef DEBUG_WAITLIST
+#define CHECK_WAITLIST(S,O) autofs_check_waitlist_integrity(S,O)
+void autofs_check_waitlist_integrity(struct autofs_sb_info *,char *);
+#else
+#define CHECK_WAITLIST(S,O)
+#endif
+
/* Hash operations */
autofs_hash_t autofs_hash(const char *,int);
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index a8c176a02..20ca0907a 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -150,6 +150,7 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
s->u.generic_sbp = sbi;
+ sbi->magic = AUTOFS_SBI_MAGIC;
sbi->catatonic = 0;
sbi->exp_timeout = 0;
sbi->oz_pgrp = current->pgrp;
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 57449e816..69e62f823 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -190,30 +190,33 @@ static int autofs_root_symlink(struct inode *dir, const char *name, int len, con
DPRINTK(("autofs_root_symlink: %s <- ", symname));
autofs_say(name,len);
- iput(dir);
-
- if ( !autofs_oz_mode(sbi) )
+ if ( !autofs_oz_mode(sbi) ) {
+ iput(dir);
return -EPERM;
-
- if ( autofs_hash_lookup(dh,hash,name,len) )
+ }
+ if ( autofs_hash_lookup(dh,hash,name,len) ) {
+ iput(dir);
return -EEXIST;
-
+ }
n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS);
- if ( n >= AUTOFS_MAX_SYMLINKS )
+ if ( n >= AUTOFS_MAX_SYMLINKS ) {
+ iput(dir);
return -ENOSPC;
-
+ }
set_bit(n,sbi->symlink_bitmap);
sl = &sbi->symlink[n];
sl->len = strlen(symname);
sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL);
if ( !sl->data ) {
clear_bit(n,sbi->symlink_bitmap);
+ iput(dir);
return -ENOSPC;
}
ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
if ( !ent ) {
kfree(sl->data);
clear_bit(n,sbi->symlink_bitmap);
+ iput(dir);
return -ENOSPC;
}
ent->name = kmalloc(len, GFP_KERNEL);
@@ -221,6 +224,7 @@ static int autofs_root_symlink(struct inode *dir, const char *name, int len, con
kfree(sl->data);
kfree(ent);
clear_bit(n,sbi->symlink_bitmap);
+ iput(dir);
return -ENOSPC;
}
memcpy(sl->data,symname,slsize);
@@ -231,6 +235,7 @@ static int autofs_root_symlink(struct inode *dir, const char *name, int len, con
memcpy(ent->name,name,ent->len = len);
autofs_hash_insert(dh,ent);
+ iput(dir);
return 0;
}
@@ -243,15 +248,19 @@ static int autofs_root_unlink(struct inode *dir, const char *name, int len)
struct autofs_dir_ent *ent;
unsigned int n;
+ iput(dir); /* Nothing below can sleep */
+
if ( !autofs_oz_mode(sbi) )
return -EPERM;
ent = autofs_hash_lookup(dh,hash,name,len);
if ( !ent )
return -ENOENT;
+
n = ent->ino - AUTOFS_FIRST_SYMLINK;
if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap) )
return -EINVAL; /* Not a symlink inode, can't unlink */
+
autofs_hash_delete(ent);
clear_bit(n,sbi->symlink_bitmap);
kfree(sbi->symlink[n].data);
diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c
index b37745f19..719e04eb4 100644
--- a/fs/autofs/waitq.c
+++ b/fs/autofs/waitq.c
@@ -16,6 +16,46 @@
#include <linux/file.h>
#include "autofs_i.h"
+#ifdef DEBUG_WAITLIST
+#ifndef i386
+#error Only i386 implemented
+#endif
+
+static inline int sane_pointer(void *p)
+{
+ return (p == NULL) || ((unsigned) p > 0xc0000000);
+}
+
+void autofs_check_waitlist_integrity(struct autofs_sb_info *sbi, char *op)
+{
+ struct autofs_wait_queue **wqp, *wq;
+
+ if ( sbi->magic != AUTOFS_SBI_MAGIC ) {
+ printk("autofs: CHECK_WAITLIST with bogus sbi pointer: %p\n",
+ sbi);
+ return;
+ }
+
+ wqp = &(sbi->queues);
+ while ( (wq = *wqp) ) {
+ if ( !sane_pointer(wq) ) {
+ printk("autofs(%s): wait queue pointer corrupt: ", op);
+ wqp = &(sbi->queues);
+ do {
+ wq = *wqp;
+ printk(" %p", wq);
+ wqp = &(wq->next);
+ } while ( sane_pointer(*wqp) );
+ printk("\n");
+ *wqp = NULL;
+ break;
+ } else {
+ wqp = &(wq->next);
+ }
+ }
+}
+#endif
+
/* We make this a static variable rather than a part of the superblock; it
is better if we don't reassign numbers easily even across filesystems */
static int autofs_next_wait_queue = 1;
@@ -95,6 +135,8 @@ int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name
struct autofs_wait_queue *wq;
int status;
+ CHECK_WAITLIST(sbi,"wait");
+
for ( wq = sbi->queues ; wq ; wq = wq->next ) {
if ( wq->hash == hash &&
wq->len == len &&
@@ -148,6 +190,8 @@ int autofs_wait_release(struct autofs_sb_info *sbi, unsigned long wait_queue_tok
{
struct autofs_wait_queue *wq, **wql;
+ CHECK_WAITLIST(sbi,"release");
+
for ( wql = &sbi->queues ; (wq = *wql) ; wql = &wq->next ) {
if ( wq->wait_queue_token == wait_queue_token )
break;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 3c17b6eec..4e2de9cfc 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -178,7 +178,7 @@ nfs_writepage_sync(struct inode *inode, struct page *page,
wsize = count;
result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode),
- offset, wsize, IS_SWAPFILE(inode),
+ IS_SWAPFILE(inode), offset, wsize,
buffer, &fattr);
if (result < 0) {
diff --git a/fs/proc/array.c b/fs/proc/array.c
index f8d5d3464..516e87813 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -297,20 +297,14 @@ static int get_uptime(char * buffer)
static int get_meminfo(char * buffer)
{
struct sysinfo i;
- int len;
si_meminfo(&i);
si_swapinfo(&i);
- len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n"
- "Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n"
- "Swap: %8lu %8lu %8lu\n",
- i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, page_cache_size*PAGE_SIZE,
- i.totalswap, i.totalswap-i.freeswap, i.freeswap);
+
/*
- * Tagged format, for easy grepping and expansion. The above will go away
- * eventually, once the tools have been updated.
+ * Tagged format, for easy grepping and expansion.
*/
- return len + sprintf(buffer+len,
+ return sprintf(buffer,
"MemTotal: %8lu kB\n"
"MemFree: %8lu kB\n"
"MemShared: %8lu kB\n"