diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/autofs/autofs_i.h | 14 | ||||
-rw-r--r-- | fs/autofs/inode.c | 1 | ||||
-rw-r--r-- | fs/autofs/root.c | 25 | ||||
-rw-r--r-- | fs/autofs/waitq.c | 44 | ||||
-rw-r--r-- | fs/nfs/write.c | 2 | ||||
-rw-r--r-- | fs/proc/array.c | 12 |
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" |