diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
commit | b9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch) | |
tree | 42d07b0c7246ae2536a702e7c5de9e2732341116 /fs | |
parent | 7406b0a326f2d70ade2671c37d1beef62249db97 (diff) |
Merge with 2.3.99-pre6.
Diffstat (limited to 'fs')
102 files changed, 2017 insertions, 1922 deletions
diff --git a/fs/Config.in b/fs/Config.in index 53029b7d3..b553ca32c 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -12,7 +12,7 @@ tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL dep_mbool ' ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL -tristate 'Amiga FFS file system support' CONFIG_AFFS_FS +dep_tristate 'Amiga FFS file system support (EXPERIMENTAL)' CONFIG_AFFS_FS $CONFIG_EXPERIMENTAL dep_tristate 'Apple Macintosh file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index c9aecc730..20e05fd5c 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -49,7 +49,7 @@ abort_toobig: return 0; } -static int adfs_writepage(struct dentry *dentry, struct page *page) +static int adfs_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page, adfs_get_block); } @@ -73,6 +73,7 @@ static int _adfs_bmap(struct address_space *mapping, long block) static struct address_space_operations adfs_aops = { readpage: adfs_readpage, writepage: adfs_writepage, + sync_page: block_sync_page, prepare_write: adfs_prepare_write, commit_write: generic_commit_write, bmap: _adfs_bmap diff --git a/fs/affs/Changes b/fs/affs/Changes index 7a7faedd0..49fe517ff 100644 --- a/fs/affs/Changes +++ b/fs/affs/Changes @@ -28,6 +28,12 @@ Known bugs: Please direct bug reports to: hjw@zvw.de +Version 3.11 +------------ + +- Converted to use 2.3.x page cache [Dave Jones <dave@powertweak.com>] +- Corruption in truncate() bugfix [Ken Tyler <kent@werple.net.au>] + Version 3.10 ------------ diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c index 718a73970..3382a82f9 100644 --- a/fs/affs/bitmap.c +++ b/fs/affs/bitmap.c @@ -280,28 +280,17 @@ s32 affs_new_header(struct inode *inode) { s32 block; - struct buffer_head *bh; pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino); if (!(block = affs_balloc(inode,0))) { while (affs_find_new_zone(inode->i_sb,0)) { if ((block = affs_balloc(inode,0))) - goto init_block; + return block; schedule(); } return 0; } -init_block: - if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { - affs_error(inode->i_sb,"new_header","Cannot get block %d",block); - return 0; - } - memset(bh->b_data,0,AFFS_I2BSIZE(inode)); - mark_buffer_uptodate(bh,1); - mark_buffer_dirty(bh,1); - affs_brelse(bh); - return block; } @@ -314,7 +303,6 @@ affs_new_data(struct inode *inode) unsigned long oldest; struct affs_zone *zone; struct super_block *sb; - struct buffer_head *bh; int i = 0; s32 block; @@ -327,7 +315,7 @@ affs_new_data(struct inode *inode) unlock_super(sb); block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]; inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1; - goto init_block; + return block; } unlock_super(sb); oldest = jiffies; @@ -364,24 +352,13 @@ found: if (!(block = affs_balloc(inode,i))) { /* No data zones left */ while (affs_find_new_zone(sb,i)) { if ((block = affs_balloc(inode,i))) - goto init_block; + return block; schedule(); } inode->u.affs_i.i_zone = 0; zone->z_ino = -1; return 0; } - -init_block: - if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) { - affs_error(inode->i_sb,"new_data","Cannot get block %d",block); - return 0; - } - memset(bh->b_data,0,sb->s_blocksize); - mark_buffer_uptodate(bh,1); - mark_buffer_dirty(bh,1); - affs_brelse(bh); - return block; } diff --git a/fs/affs/file.c b/fs/affs/file.c index bc0db190f..251853a54 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -13,6 +13,7 @@ */ #define DEBUG 0 +#include <asm/div64.h> #include <asm/uaccess.h> #include <asm/system.h> #include <linux/sched.h> @@ -23,6 +24,7 @@ #include <linux/malloc.h> #include <linux/stat.h> #include <linux/locks.h> +#include <linux/smp_lock.h> #include <linux/dirent.h> #include <linux/fs.h> #include <linux/amigaffs.h> @@ -36,7 +38,6 @@ #error PAGE_SIZE must be at least 4096 #endif -static int affs_bmap(struct inode *inode, int block); static struct buffer_head *affs_getblock(struct inode *inode, s32 block); static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos); static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos); @@ -157,6 +158,8 @@ calc_key(struct inode *inode, int *ext) for (index = 0; index < 4; index++) { kc = &inode->u.affs_i.i_ec->kc[index]; + if (kc->kc_last == -1) + continue; /* don't look in cache if invalid. */ if (*ext == kc->kc_this_seq) { return kc->kc_this_key; } else if (*ext == kc->kc_this_seq + 1) { @@ -175,7 +178,7 @@ calc_key(struct inode *inode, int *ext) return inode->u.affs_i.i_ec->ec[index]; } -static int +int affs_bmap(struct inode *inode, int block) { struct buffer_head *bh; @@ -192,13 +195,14 @@ affs_bmap(struct inode *inode, int block) pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block); + lock_kernel(); if (block < 0) { affs_error(inode->i_sb,"bmap","Block < 0"); - return 0; + goto out_fail; } if (!inode->u.affs_i.i_ec) { if (alloc_ext_cache(inode)) { - return 0; + goto out_fail; } } @@ -212,6 +216,7 @@ affs_bmap(struct inode *inode, int block) tkc = &inode->u.affs_i.i_ec->kc[i]; /* Look in any cache if the key is there */ if (block <= tkc->kc_last && block >= tkc->kc_first) { + unlock_kernel(); return tkc->kc_keys[block - tkc->kc_first]; } } @@ -246,14 +251,15 @@ affs_bmap(struct inode *inode, int block) for (;;) { bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); - if (!bh) - return 0; + if (!bh) + goto out_fail; + index = seqnum_to_index(ext); if (index > inode->u.affs_i.i_ec->max_ext && (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE)) { affs_brelse(bh); - return 0; + goto out_fail; } nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); if (block < AFFS_I2HSIZE(inode)) { @@ -282,16 +288,57 @@ affs_bmap(struct inode *inode, int block) kc->kc_next_key = nkey; key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block)); affs_brelse(bh); +out: + unlock_kernel(); return key; + +out_fail: + key=0; + goto out; } -/* AFFS is currently broken */ -static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create) + +static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create) { - BUG(); - return -1; + int err, phys=0, new=0; + + if (!create) { + phys = affs_bmap(inode, block); + if (phys) { + bh_result->b_dev = inode->i_dev; + bh_result->b_blocknr = phys; + bh_result->b_state |= (1UL << BH_Mapped); + } + return 0; + } + + err = -EIO; + lock_kernel(); + if (block < 0) + goto abort_negative; + + if (affs_getblock(inode, block)==NULL) { + err = -EIO; + goto abort; + } + + bh_result->b_dev = inode->i_dev; + bh_result->b_blocknr = phys; + bh_result->b_state |= (1UL << BH_Mapped); + if (new) + bh_result->b_state |= (1UL << BH_New); + +abort: + unlock_kernel(); + return err; + +abort_negative: + affs_error(inode->i_sb,"affs_get_block","Block < 0"); + goto abort; + } -static int affs_writepage(struct dentry *dentry, struct page *page) + +static int affs_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,affs_get_block); } @@ -311,6 +358,7 @@ static int _affs_bmap(struct address_space *mapping, long block) struct address_space_operations affs_aops = { readpage: affs_readpage, writepage: affs_writepage, + sync_page: block_sync_page, prepare_write: affs_prepare_write, commit_write: generic_commit_write, bmap: _affs_bmap @@ -325,8 +373,7 @@ struct address_space_operations affs_aops = { * What a mess. */ -static struct buffer_head * -affs_getblock(struct inode *inode, s32 block) +static struct buffer_head * affs_getblock(struct inode *inode, s32 block) { struct super_block *sb = inode->i_sb; int ofs = sb->u.affs_sb.s_flags & SF_OFS; @@ -340,9 +387,6 @@ affs_getblock(struct inode *inode, s32 block) pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block); - if (block < 0) - goto out_fail; - key = calc_key(inode,&ext); block -= ext * AFFS_I2HSIZE(inode); pt = ext ? T_LIST : T_SHORT; @@ -370,16 +414,14 @@ affs_getblock(struct inode *inode, s32 block) for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) { if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) { if (j > 0) { - s32 k = AFFS_BLOCK(bh->b_data, inode, - j - 1); + s32 k = AFFS_BLOCK(bh->b_data, inode, j - 1); pbh = affs_bread(inode->i_dev, be32_to_cpu(k), AFFS_I2BSIZE(inode)); } else pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock); if (!pbh) { - affs_error(sb,"getblock", - "Cannot get last block in file"); + affs_error(sb,"getblock", "Cannot get last block in file"); break; } } @@ -396,8 +438,7 @@ affs_getblock(struct inode *inode, s32 block) if (ofs) { ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode)); if (!ebh) { - affs_error(sb,"getblock", - "Cannot get block %d",nkey); + affs_error(sb,"getblock", "Cannot get block %d",nkey); affs_free_block(sb,nkey); AFFS_BLOCK(bh->b_data,inode,j) = 0; break; @@ -405,8 +446,7 @@ affs_getblock(struct inode *inode, s32 block) DATA_FRONT(ebh)->primary_type = cpu_to_be32(T_DATA); DATA_FRONT(ebh)->header_key = cpu_to_be32(inode->i_ino); DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1); - affs_fix_checksum(AFFS_I2BSIZE(inode), - ebh->b_data, 5); + affs_fix_checksum(AFFS_I2BSIZE(inode), ebh->b_data, 5); mark_buffer_dirty(ebh, 0); if (pbh) { DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24); @@ -503,6 +543,7 @@ affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos) ssize_t blocksize; struct buffer_head *bh; void *data; + loff_t tmp; pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino, (unsigned long)*ppos,count); @@ -524,10 +565,13 @@ affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos) left = MIN (inode->i_size - *ppos,count - (buf - start)); if (!left) break; - sector = affs_bmap(inode,(u32)*ppos / blocksize); + tmp = *ppos; + do_div(tmp, blocksize); + sector = affs_bmap(inode, tmp); if (!sector) break; - offset = (u32)*ppos % blocksize; + tmp = *ppos; + offset = do_div(tmp, blocksize); bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode)); if (!bh) break; @@ -544,165 +588,31 @@ affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos) } static ssize_t -affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) +affs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; - off_t pos; - ssize_t written; - ssize_t c; - ssize_t blocksize; - struct buffer_head *bh; - char *p; + ssize_t retval; - if (!count) - return 0; - pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, - (unsigned long)*ppos,count); - - if (!inode) { - affs_error(inode->i_sb,"file_write","Inode = NULL"); - return -EINVAL; + retval = generic_file_write (file, buf, count, ppos); + if (retval >0) { + struct inode *inode = file->f_dentry->d_inode; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); } - if (!S_ISREG(inode->i_mode)) { - affs_error(inode->i_sb,"file_write", - "Trying to write to non-regular file (mode=%07o)", - inode->i_mode); - return -EINVAL; - } - if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) - return -ENOMEM; - if (filp->f_flags & O_APPEND) - pos = inode->i_size; - else - pos = *ppos; - written = 0; - blocksize = AFFS_I2BSIZE(inode); - - while (written < count) { - bh = affs_getblock(inode,pos / blocksize); - if (!bh) { - if (!written) - written = -ENOSPC; - break; - } - c = blocksize - (pos % blocksize); - if (c > count - written) - c = count - written; - if (c != blocksize && !buffer_uptodate(bh)) { - ll_rw_block(READ,1,&bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - affs_brelse(bh); - if (!written) - written = -EIO; - break; - } - } - p = (pos % blocksize) + bh->b_data; - c -= copy_from_user(p,buf,c); - if (!c) { - affs_brelse(bh); - if (!written) - written = -EFAULT; - break; - } - update_vm_cache(inode,pos,p,c); - mark_buffer_uptodate(bh,1); - mark_buffer_dirty(bh,0); - affs_brelse(bh); - pos += c; - written += c; - buf += c; - } - if (pos > inode->i_size) - inode->i_size = pos; - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - *ppos = pos; - mark_inode_dirty(inode); - return written; + return retval; } static ssize_t -affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos) +affs_file_write_ofs(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; - off_t pos; - ssize_t written; - ssize_t c; - ssize_t blocksize; - struct buffer_head *bh; - char *p; + ssize_t retval; - pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, - (unsigned long)*ppos,count); - - if (!count) - return 0; - if (!inode) { - affs_error(inode->i_sb,"file_write_ofs","Inode = NULL"); - return -EINVAL; + retval = generic_file_write (file, buf, count, ppos); + if (retval >0) { + struct inode *inode = file->f_dentry->d_inode; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); } - if (!S_ISREG(inode->i_mode)) { - affs_error(inode->i_sb,"file_write_ofs", - "Trying to write to non-regular file (mode=%07o)", - inode->i_mode); - return -EINVAL; - } - if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) - return -ENOMEM; - if (filp->f_flags & O_APPEND) - pos = inode->i_size; - else - pos = *ppos; - - bh = NULL; - blocksize = AFFS_I2BSIZE(inode) - 24; - written = 0; - while (written < count) { - bh = affs_getblock(inode,pos / blocksize); - if (!bh) { - if (!written) - written = -ENOSPC; - break; - } - c = blocksize - (pos % blocksize); - if (c > count - written) - c = count - written; - if (c != blocksize && !buffer_uptodate(bh)) { - ll_rw_block(READ,1,&bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - affs_brelse(bh); - if (!written) - written = -EIO; - break; - } - } - p = (pos % blocksize) + bh->b_data + 24; - c -= copy_from_user(p,buf,c); - if (!c) { - affs_brelse(bh); - if (!written) - written = -EFAULT; - break; - } - update_vm_cache(inode,pos,p,c); - - pos += c; - buf += c; - written += c; - DATA_FRONT(bh)->data_size = cpu_to_be32(be32_to_cpu(DATA_FRONT(bh)->data_size) + c); - affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); - mark_buffer_uptodate(bh,1); - mark_buffer_dirty(bh,0); - affs_brelse(bh); - } - if (pos > inode->i_size) - inode->i_size = pos; - *ppos = pos; - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - return written; + return retval; } /* Free any preallocated blocks. */ @@ -746,11 +656,13 @@ affs_truncate(struct inode *inode) int blocksize = AFFS_I2BSIZE(inode); int rem; int ext; + loff_t tmp; pr_debug("AFFS: truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size); net_blocksize = blocksize - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0); - first = (inode->i_size + net_blocksize - 1) / net_blocksize; + first = inode->i_size + net_blocksize -1; + do_div (first, net_blocksize); if (inode->u.affs_i.i_lastblock < first - 1) { /* There has to be at least one new block to be allocated */ if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) { @@ -762,7 +674,8 @@ affs_truncate(struct inode *inode) affs_warning(inode->i_sb,"truncate","Cannot extend file"); inode->i_size = net_blocksize * (inode->u.affs_i.i_lastblock + 1); } else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) { - rem = inode->i_size % net_blocksize; + tmp = inode->i_size; + rem = do_div(tmp, net_blocksize); DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize); affs_fix_checksum(blocksize,bh->b_data,5); mark_buffer_dirty(bh,0); @@ -829,7 +742,9 @@ affs_truncate(struct inode *inode) affs_free_block(inode->i_sb,ekey); ekey = key; } - block = ((inode->i_size + net_blocksize - 1) / net_blocksize) - 1; + block = inode->i_size + net_blocksize - 1; + do_div (block, net_blocksize); + block--; inode->u.affs_i.i_lastblock = block; /* If the file is not truncated to a block boundary, @@ -837,7 +752,8 @@ affs_truncate(struct inode *inode) * so it cannot become accessible again. */ - rem = inode->i_size % net_blocksize; + tmp = inode->i_size; + rem = do_div(tmp, net_blocksize); if (rem) { if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) rem += 24; @@ -860,7 +776,7 @@ out_truncate: /* Invalidate cache */ if (inode->u.affs_i.i_ec) { inode->u.affs_i.i_ec->max_ext = 0; - for (key = 0; key < 3; key++) { + for (key = 0; key < 4; key++) { inode->u.affs_i.i_ec->kc[key].kc_next_key = 0; inode->u.affs_i.i_ec->kc[key].kc_last = -1; } diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 780b99ad3..b76857603 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -11,6 +11,7 @@ */ #define DEBUG 0 +#include <asm/div64.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/malloc.h> @@ -59,6 +60,7 @@ affs_read_inode(struct inode *inode) unsigned long prot; s32 ptype, stype; unsigned short id; + loff_t tmp; pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino); @@ -147,7 +149,10 @@ affs_read_inode(struct inode *inode) block = AFFS_I2BSIZE(inode) - 24; else block = AFFS_I2BSIZE(inode); - inode->u.affs_i.i_lastblock = ((inode->i_size + block - 1) / block) - 1; + tmp = inode->i_size + block -1; + do_div (tmp, block); + tmp--; + inode->u.affs_i.i_lastblock = tmp; break; case ST_SOFTLINK: inode->i_mode |= S_IFLNK; diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h index 51305918b..cfd74c9d5 100644 --- a/fs/autofs/autofs_i.h +++ b/fs/autofs/autofs_i.h @@ -56,13 +56,12 @@ struct autofs_dir_ent { struct autofs_dir_ent **back; /* The following entries are for the expiry system */ unsigned long last_usage; - struct autofs_dir_ent *exp_next; - struct autofs_dir_ent *exp_prev; + struct list_head exp; }; struct autofs_dirhash { struct autofs_dir_ent *h[AUTOFS_HASH_SIZE]; - struct autofs_dir_ent expiry_head; + struct list_head expiry_head; }; struct autofs_wait_queue { diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c index b5626e5bb..6dc3e4f60 100644 --- a/fs/autofs/dirhash.c +++ b/fs/autofs/dirhash.c @@ -17,17 +17,13 @@ static void autofs_init_usage(struct autofs_dirhash *dh, struct autofs_dir_ent *ent) { - ent->exp_next = &dh->expiry_head; - ent->exp_prev = dh->expiry_head.exp_prev; - dh->expiry_head.exp_prev->exp_next = ent; - dh->expiry_head.exp_prev = ent; + list_add_tail(&ent->exp, &dh->expiry_head); ent->last_usage = jiffies; } static void autofs_delete_usage(struct autofs_dir_ent *ent) { - ent->exp_prev->exp_next = ent->exp_next; - ent->exp_next->exp_prev = ent->exp_prev; + list_del(&ent->exp); } void autofs_update_usage(struct autofs_dirhash *dh, @@ -45,12 +41,13 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, struct dentry *dentry; unsigned long timeout = sbi->exp_timeout; - ent = dh->expiry_head.exp_next; - - if ( ent == &(dh->expiry_head) || sbi->catatonic ) - return NULL; /* No entries */ - - while ( jiffies - ent->last_usage >= timeout ) { + while (1) { + if ( list_empty(&dh->expiry_head) || sbi->catatonic ) + return NULL; /* No entries */ + /* We keep the list sorted by last_usage and want old stuff */ + ent = list_entry(dh->expiry_head.next, struct autofs_dir_ent, exp); + if (jiffies - ent->last_usage < timeout) + break; /* Move to end of list in case expiry isn't desirable */ autofs_update_usage(dh, ent); @@ -94,8 +91,7 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, void autofs_initialize_hash(struct autofs_dirhash *dh) { memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *)); - dh->expiry_head.exp_next = dh->expiry_head.exp_prev = - &dh->expiry_head; + INIT_LIST_HEAD(&dh->expiry_head); } struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, struct qstr *name) diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index 2c2e7d32d..ae157d1ac 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -19,19 +19,6 @@ #define __NO_VERSION__ #include <linux/module.h> -/* - * Dummy functions - do we ever actually want to do - * something here? - */ -static void autofs_put_inode(struct inode *inode) -{ -} - -static void autofs_delete_inode(struct inode *inode) -{ - inode->i_size = 0; -} - static void autofs_put_super(struct super_block *sb) { struct autofs_sb_info *sbi = autofs_sbi(sb); @@ -53,13 +40,9 @@ static void autofs_put_super(struct super_block *sb) static int autofs_statfs(struct super_block *sb, struct statfs *buf); static void autofs_read_inode(struct inode *inode); -static void autofs_write_inode(struct inode *inode); static struct super_operations autofs_sops = { read_inode: autofs_read_inode, - write_inode: autofs_write_inode, - put_inode: autofs_put_inode, - delete_inode: autofs_delete_inode, put_super: autofs_put_super, statfs: autofs_statfs, }; @@ -137,10 +120,6 @@ struct super_block *autofs_read_super(struct super_block *s, void *data, struct autofs_sb_info *sbi; int minproto, maxproto; - /* Super block already completed? */ - if (s->s_root) - goto out_unlock; - sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL); if ( !sbi ) goto fail_unlock; @@ -159,25 +138,15 @@ struct super_block *autofs_read_super(struct super_block *s, void *data, s->s_blocksize_bits = 10; s->s_magic = AUTOFS_SUPER_MAGIC; s->s_op = &autofs_sops; - s->s_root = NULL; - /* - * Get the root inode and dentry, but defer checking for errors. - */ root_inode = iget(s, AUTOFS_ROOT_INO); root = d_alloc_root(root_inode); pipe = NULL; - /* - * Check whether somebody else completed the super block. - */ - if (s->s_root) - goto out_dput; - if (!root) goto fail_iput; - /* Can this call block? */ + /* Can this call block? - WTF cares? s is locked. */ if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) { printk("autofs: called with bogus options\n"); goto fail_dput; @@ -192,11 +161,6 @@ struct super_block *autofs_read_super(struct super_block *s, void *data, DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp)); pipe = fget(pipefd); - /* - * Check whether somebody else completed the super block. - */ - if (s->s_root) - goto out_fput; if ( !pipe ) { printk("autofs: could not open pipe file descriptor\n"); @@ -212,43 +176,14 @@ struct super_block *autofs_read_super(struct super_block *s, void *data, s->s_root = root; return s; - /* - * Success ... somebody else completed the super block for us. - */ -out_unlock: - goto out_dec; -out_fput: - if (pipe) - fput(pipe); -out_dput: - if (root) - dput(root); - else - iput(root_inode); -out_dec: - return s; - - /* - * Failure ... clear the s_dev slot and clean up. - */ fail_fput: printk("autofs: pipe file descriptor does not contain proper ops\n"); - /* - * fput() can block, so we clear the super block first. - */ fput(pipe); - /* fall through */ fail_dput: - /* - * dput() can block, so we clear the super block first. - */ dput(root); goto fail_free; fail_iput: printk("autofs: get root dentry failed\n"); - /* - * iput() can block, so we clear the super block first. - */ iput(root_inode); fail_free: kfree(sbi); @@ -260,9 +195,6 @@ static int autofs_statfs(struct super_block *sb, struct statfs *buf) { buf->f_type = AUTOFS_SUPER_MAGIC; buf->f_bsize = 1024; - buf->f_bfree = 0; - buf->f_bavail = 0; - buf->f_ffree = 0; buf->f_namelen = NAME_MAX; return 0; } @@ -314,7 +246,3 @@ static void autofs_read_inode(struct inode *inode) inode->i_nlink = 1; } } - -static void autofs_write_inode(struct inode *inode) -{ -} diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 06e2e86ea..baa8cd6bf 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -186,7 +186,7 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr autofs_say(dentry->d_name.name,dentry->d_name.len); if (dentry->d_name.len > NAME_MAX) - return ERR_PTR(-ENOENT);/* File name too long to exist */ + return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */ sbi = autofs_sbi(dir->i_sb); @@ -248,9 +248,6 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c if ( !autofs_oz_mode(sbi) ) return -EACCES; - if ( dentry->d_name.len > NAME_MAX ) - return -ENAMETOOLONG; - if ( autofs_hash_lookup(dh, &dentry->d_name) ) return -EEXIST; @@ -375,9 +372,6 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) if ( !autofs_oz_mode(sbi) ) return -EACCES; - if ( dentry->d_name.len > NAME_MAX ) - return -ENAMETOOLONG; - ent = autofs_hash_lookup(dh, &dentry->d_name); if ( ent ) return -EEXIST; diff --git a/fs/autofs4/Makefile b/fs/autofs4/Makefile index 0095b8aed..3e3f2cc22 100644 --- a/fs/autofs4/Makefile +++ b/fs/autofs4/Makefile @@ -5,7 +5,7 @@ # O_TARGET := autofs4.o -O_OBJS := inohash.o init.o inode.o root.o symlink.o waitq.o expire.o +O_OBJS := init.o inode.o root.o symlink.o waitq.o expire.o M_OBJS := $(O_TARGET) diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index b55afd6c4..bc23ed145 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -1,4 +1,4 @@ -/* -*- linux-c -*- ------------------------------------------------------- * +/* -*- c -*- ------------------------------------------------------------- * * * linux/fs/autofs/autofs_i.h * @@ -57,10 +57,8 @@ struct autofs_info { int flags; struct autofs_sb_info *sbi; - struct list_head ino_hash; unsigned long last_used; - ino_t ino; mode_t mode; size_t size; @@ -72,10 +70,6 @@ struct autofs_info { #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ -struct autofs_inohash { - struct list_head head; -}; - struct autofs_wait_queue { wait_queue_head_t queue; struct autofs_wait_queue *next; @@ -89,9 +83,6 @@ struct autofs_wait_queue { int wait_ctr; }; -#define AUTOFS_ROOT_INO 1 -#define AUTOFS_FIRST_INO 2 - #define AUTOFS_SBI_MAGIC 0x6d4a556d struct autofs_sb_info { @@ -101,10 +92,8 @@ struct autofs_sb_info { int catatonic; int version; unsigned long exp_timeout; - ino_t next_ino; struct super_block *sb; struct autofs_wait_queue *queues; /* Wait queue pointer */ - struct autofs_inohash ihash; }; static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb) @@ -134,13 +123,7 @@ static inline int autofs4_ispending(struct dentry *dentry) (inf != NULL && inf->flags & AUTOFS_INF_EXPIRING); } -/* Inode hash operations */ -void autofs4_init_ihash(struct autofs_inohash *); -void autofs4_ihash_insert(struct autofs_inohash *ih, struct autofs_info *ino); -void autofs4_ihash_delete(struct autofs_info *ino); -void autofs4_ihash_nuke(struct autofs_inohash *ih); -struct autofs_info *autofs4_ihash_find(struct autofs_inohash *ih, ino_t ino); - +struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *); struct autofs_info *autofs4_init_inf(struct autofs_sb_info *, mode_t mode); void autofs4_free_ino(struct autofs_info *); diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index dd3695648..e93557db8 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -1,4 +1,4 @@ -/* -*- linux-c -*- --------------------------------------------------------- * +/* -*- c -*- --------------------------------------------------------------- * * * linux/fs/autofs/expire.c * @@ -46,8 +46,9 @@ static int is_tree_busy(struct dentry *root) count--; } - /* Mountpoints don't count */ - if (d_mountpoint(root)) { + /* Mountpoints don't count (either mountee or mounter) */ + if (d_mountpoint(root) || + root != root->d_covers) { DPRINTK(("is_tree_busy: mountpoint\n")); count--; } @@ -75,9 +76,11 @@ resume: /* Decrement count for unused children */ count += (dentry->d_count - 1); - /* Mountpoints don't count */ - if (d_mountpoint(dentry)) { - DPRINTK(("is_tree_busy: mountpoint\n")); + /* Mountpoints don't count (either mountee or mounter) */ + if (d_mountpoint(dentry) || + dentry != dentry->d_covers) { + DPRINTK(("is_tree_busy: mountpoint dentry=%p covers=%p mounts=%p\n", + dentry, dentry->d_covers, dentry->d_mounts)); adj++; } diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c index baf12d913..dc63926ad 100644 --- a/fs/autofs4/init.c +++ b/fs/autofs4/init.c @@ -1,4 +1,4 @@ -/* -*- linux-c -*- --------------------------------------------------------- * +/* -*- c -*- --------------------------------------------------------------- * * * linux/fs/autofs/init.c * diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index b4ea73fdb..077df4c2b 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -1,4 +1,4 @@ -/* -*- linux-c -*- --------------------------------------------------------- * +/* -*- c -*- --------------------------------------------------------------- * * * linux/fs/autofs/inode.c * @@ -41,7 +41,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, return NULL; ino->flags = 0; - ino->ino = sbi->next_ino++; ino->mode = mode; ino->inode = NULL; ino->dentry = NULL; @@ -50,7 +49,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, ino->last_used = jiffies; ino->sbi = sbi; - INIT_LIST_HEAD(&ino->ino_hash); if (reinit && ino->free) (ino->free)(ino); @@ -67,7 +65,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, void autofs4_free_ino(struct autofs_info *ino) { - autofs4_ihash_delete(ino); if (ino->dentry) { ino->dentry->d_fsdata = NULL; if (ino->dentry->d_inode) @@ -79,18 +76,6 @@ void autofs4_free_ino(struct autofs_info *ino) kfree(ino); } -/* - * Dummy functions - do we ever actually want to do - * something here? - */ -static void autofs4_put_inode(struct inode *inode) -{ -} - -static void autofs4_clear_inode(struct inode *inode) -{ -} - static void autofs4_put_super(struct super_block *sb) { struct autofs_sb_info *sbi = autofs4_sbi(sb); @@ -105,26 +90,11 @@ static void autofs4_put_super(struct super_block *sb) DPRINTK(("autofs: shutting down\n")); } -static void autofs4_umount_begin(struct super_block *sb) -{ - struct autofs_sb_info *sbi = autofs4_sbi(sb); - - if (!sbi->catatonic) - autofs4_catatonic_mode(sbi); -} - static int autofs4_statfs(struct super_block *sb, struct statfs *buf); -static void autofs4_read_inode(struct inode *inode); -static void autofs4_write_inode(struct inode *inode); static struct super_operations autofs4_sops = { - read_inode: autofs4_read_inode, - write_inode: autofs4_write_inode, - put_inode: autofs4_put_inode, - clear_inode: autofs4_clear_inode, put_super: autofs4_put_super, statfs: autofs4_statfs, - umount_begin: autofs4_umount_begin, }; static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, @@ -200,8 +170,6 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi) if (!ino) return NULL; - ino->ino = AUTOFS_ROOT_INO; - return ino; } @@ -215,10 +183,6 @@ struct super_block *autofs4_read_super(struct super_block *s, void *data, struct autofs_sb_info *sbi; int minproto, maxproto; - /* Super block already completed? */ - if (s->s_root) - goto out_unlock; - sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL); if ( !sbi ) goto fail_unlock; @@ -233,30 +197,21 @@ struct super_block *autofs4_read_super(struct super_block *s, void *data, sbi->oz_pgrp = current->pgrp; sbi->sb = s; sbi->version = 0; - autofs4_init_ihash(&sbi->ihash); sbi->queues = NULL; - sbi->next_ino = AUTOFS_FIRST_INO; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = AUTOFS_SUPER_MAGIC; s->s_op = &autofs4_sops; - s->s_root = NULL; /* * Get the root inode and dentry, but defer checking for errors. */ - autofs4_ihash_insert(&sbi->ihash, autofs4_mkroot(sbi)); - - root_inode = iget(s, AUTOFS_ROOT_INO); + root_inode = autofs4_get_inode(s, autofs4_mkroot(sbi)); + root_inode->i_op = &autofs4_root_inode_operations; + root_inode->i_fop = &autofs4_root_operations; root = d_alloc_root(root_inode); pipe = NULL; - /* - * Check whether somebody else completed the super block. - */ - if (s->s_root) - goto out_dput; - if (!root) goto fail_iput; @@ -283,11 +238,6 @@ struct super_block *autofs4_read_super(struct super_block *s, void *data, DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp)); pipe = fget(pipefd); - /* - * Check whether somebody else completed the super block. - */ - if (s->s_root) - goto out_fput; if ( !pipe ) { printk("autofs: could not open pipe file descriptor\n"); @@ -302,25 +252,9 @@ struct super_block *autofs4_read_super(struct super_block *s, void *data, */ s->s_root = root; return s; - - /* - * Success ... somebody else completed the super block for us. - */ -out_unlock: - goto out_dec; -out_fput: - if (pipe) - fput(pipe); -out_dput: - if (root) - dput(root); - else - iput(root_inode); -out_dec: - return s; /* - * Failure ... clear the s_dev slot and clean up. + * Failure ... clean up. */ fail_fput: printk("autofs: pipe file descriptor does not contain proper ops\n"); @@ -351,55 +285,44 @@ static int autofs4_statfs(struct super_block *sb, struct statfs *buf) { buf->f_type = AUTOFS_SUPER_MAGIC; buf->f_bsize = 1024; - buf->f_bfree = 0; - buf->f_bavail = 0; - buf->f_ffree = 0; buf->f_namelen = NAME_MAX; return 0; } -static void autofs4_read_inode(struct inode *inode) +struct inode *autofs4_get_inode(struct super_block *sb, + struct autofs_info *inf) { - struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb); - struct autofs_info *inf; + struct inode *inode = get_empty_inode(); - inf = autofs4_ihash_find(&sbi->ihash, inode->i_ino); - - if (inf == NULL || inf->inode != NULL) - return; + if (inode == NULL) + return NULL; + inf->inode = inode; + inode->i_sb = sb; + inode->i_dev = sb->s_dev; inode->i_mode = inf->mode; - inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME; - inode->i_size = inf->size; - - inode->i_blocks = 0; - inode->i_blksize = 0; - inode->i_nlink = 1; - - if (inode->i_sb->s_root) { - inode->i_uid = inode->i_sb->s_root->d_inode->i_uid; - inode->i_gid = inode->i_sb->s_root->d_inode->i_gid; + if (sb->s_root) { + inode->i_uid = sb->s_root->d_inode->i_uid; + inode->i_gid = sb->s_root->d_inode->i_gid; } else { inode->i_uid = 0; inode->i_gid = 0; } - - inf->inode = inode; + inode->i_size = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = 0; + inode->i_nlink = 1; + inode->i_op = NULL; + inode->i_fop = NULL; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; if (S_ISDIR(inf->mode)) { inode->i_nlink = 2; - if (inode->i_ino == AUTOFS_ROOT_INO) { - inode->i_op = &autofs4_root_inode_operations; - inode->i_fop = &autofs4_root_operations; - } else { - inode->i_op = &autofs4_dir_inode_operations; - inode->i_fop = &autofs4_dir_operations; - } - } else if (S_ISLNK(inf->mode)) { + inode->i_op = &autofs4_dir_inode_operations; + inode->i_fop = &autofs4_dir_operations; + } else if (S_ISLNK(inf->mode)) inode->i_op = &autofs4_symlink_inode_operations; - } -} -static void autofs4_write_inode(struct inode *inode) -{ + return inode; } diff --git a/fs/autofs4/inohash.c b/fs/autofs4/inohash.c deleted file mode 100644 index 6190a55d3..000000000 --- a/fs/autofs4/inohash.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * "inohash" is a misnomer. Inodes are just stored in a single list, - * since this code is only ever asked for the most recently inserted - * inode. - * - * Copyright 1999 Jeremy Fitzhardinge <jeremy@goop.org> - */ - -#include "autofs_i.h" - -void autofs4_init_ihash(struct autofs_inohash *ih) -{ - INIT_LIST_HEAD(&ih->head); -} - -void autofs4_ihash_insert(struct autofs_inohash *ih, - struct autofs_info *ino) -{ - DPRINTK(("autofs_ihash_insert: adding ino %ld\n", ino->ino)); - - list_add(&ino->ino_hash, &ih->head); -} - -void autofs4_ihash_delete(struct autofs_info *inf) -{ - DPRINTK(("autofs_ihash_delete: deleting ino %ld\n", inf->ino)); - - if (!list_empty(&inf->ino_hash)) - list_del(&inf->ino_hash); -} - -struct autofs_info *autofs4_ihash_find(struct autofs_inohash *ih, - ino_t inum) -{ - struct list_head *tmp; - - for(tmp = ih->head.next; - tmp != &ih->head; - tmp = tmp->next) { - struct autofs_info *ino = list_entry(tmp, struct autofs_info, ino_hash); - if (ino->ino == inum) { - DPRINTK(("autofs_ihash_find: found %ld -> %p\n", - inum, ino)); - return ino; - } - } - DPRINTK(("autofs_ihash_find: didn't find %ld\n", inum)); - return NULL; -} - -void autofs4_ihash_nuke(struct autofs_inohash *ih) -{ - struct list_head *tmp = ih->head.next; - struct list_head *next; - - for(; tmp != &ih->head; tmp = next) { - struct autofs_info *ino; - - next = tmp->next; - - ino = list_entry(tmp, struct autofs_info, ino_hash); - - DPRINTK(("autofs_ihash_nuke: nuking %ld\n", ino->ino)); - autofs4_free_ino(ino); - } - INIT_LIST_HEAD(&ih->head); -} - diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 41dc98984..ab05ed7d5 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -1,4 +1,4 @@ -/* -*- linux-c -*- --------------------------------------------------------- * +/* -*- c -*- --------------------------------------------------------------- * * * linux/fs/autofs/root.c * @@ -87,7 +87,7 @@ static int autofs4_dir_readdir(struct file *filp, void *dirent, filp->f_pos = ++nr; /* fall through */ case 1: - if (filldir(dirent, "..", 2, nr, dentry->d_covers->d_parent->d_inode->i_ino) < 0) + if (filldir(dirent, "..", 2, nr, dentry->d_parent->d_inode->i_ino) < 0) return 0; filp->f_pos = ++nr; /* fall through */ @@ -175,7 +175,7 @@ static int try_to_fill_dentry(struct dentry *dentry, /* Return a negative dentry, but leave it "pending" */ return 1; } - status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT); + /* status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT); */ } /* If this is an unused directory that isn't a mount point, @@ -230,7 +230,7 @@ static int autofs4_root_revalidate(struct dentry * dentry, int flags) list_empty(&dentry->d_subdirs)) { DPRINTK(("autofs_root_revalidate: dentry=%p %.*s, emptydir\n", dentry, dentry->d_name.len, dentry->d_name.name)); - if (autofs4_oz_mode(sbi)) + if (oz_mode) return 1; else return try_to_fill_dentry(dentry, dir->i_sb, sbi); @@ -305,7 +305,7 @@ static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dent dentry->d_name.len, dentry->d_name.name)); if (dentry->d_name.len > NAME_MAX) - return ERR_PTR(-ENOENT);/* File name too long to exist */ + return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */ sbi = autofs4_sbi(dir->i_sb); @@ -323,12 +323,10 @@ static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dent * * We need to do this before we release the directory semaphore. */ - if (dir->i_ino == AUTOFS_ROOT_INO) - dentry->d_op = &autofs4_root_dentry_operations; - else - dentry->d_op = &autofs4_dentry_operations; + dentry->d_op = &autofs4_root_dentry_operations; - dentry->d_flags |= DCACHE_AUTOFS_PENDING; + if (!oz_mode) + dentry->d_flags |= DCACHE_AUTOFS_PENDING; dentry->d_fsdata = NULL; d_add(dentry, NULL); @@ -371,18 +369,9 @@ static int autofs4_dir_symlink(struct inode *dir, DPRINTK(("autofs_dir_symlink: %s <- %.*s\n", symname, dentry->d_name.len, dentry->d_name.name)); - if (!S_ISDIR(dir->i_mode)) - return -ENOTDIR; - if (!autofs4_oz_mode(sbi)) return -EACCES; - if (dentry->d_name.len > NAME_MAX) - return -ENAMETOOLONG; - - if (dentry->d_inode != NULL) - return -EEXIST; - ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555); if (ino == NULL) return -ENOSPC; @@ -397,11 +386,10 @@ static int autofs4_dir_symlink(struct inode *dir, strcpy(cp, symname); - autofs4_ihash_insert(&sbi->ihash, ino); - inode = iget(dir->i_sb,ino->ino); + inode = autofs4_get_inode(dir->i_sb, ino); d_instantiate(dentry, inode); - if (dir->i_ino == AUTOFS_ROOT_INO) + if (dir == dir->i_sb->s_root->d_inode) dentry->d_op = &autofs4_root_dentry_operations; else dentry->d_op = &autofs4_dentry_operations; @@ -434,12 +422,6 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); struct autofs_info *ino = autofs4_dentry_ino(dentry); - - if (!S_ISDIR(dir->i_mode)) - return -ENOTDIR; - - if (dentry->d_inode == NULL) - return -ENOENT; /* This allows root to remove symlinks */ if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) @@ -464,12 +446,6 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); struct autofs_info *ino = autofs4_dentry_ino(dentry); - - if (!S_ISDIR(dir->i_mode)) - return -ENOTDIR; - - if (dentry->d_inode == NULL) - return -ENOENT; if (!autofs4_oz_mode(sbi)) return -EACCES; @@ -501,18 +477,9 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) struct autofs_info *ino = autofs4_dentry_ino(dentry); struct inode *inode; - if (!S_ISDIR(dir->i_mode)) - return -ENOTDIR; - if ( !autofs4_oz_mode(sbi) ) return -EACCES; - if ( dentry->d_inode != NULL ) - return -EEXIST; - - if ( dentry->d_name.len > NAME_MAX ) - return -ENAMETOOLONG; - DPRINTK(("autofs_dir_mkdir: dentry %p, creating %.*s\n", dentry, dentry->d_name.len, dentry->d_name.name)); @@ -520,12 +487,10 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (ino == NULL) return -ENOSPC; - autofs4_ihash_insert(&sbi->ihash, ino); - - inode = iget(dir->i_sb, ino->ino); + inode = autofs4_get_inode(dir->i_sb, ino); d_instantiate(dentry, inode); - if (dir->i_ino == AUTOFS_ROOT_INO) + if (dir == dir->i_sb->s_root->d_inode) dentry->d_op = &autofs4_root_dentry_operations; else dentry->d_op = &autofs4_dentry_operations; diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c index 0bcb312e0..40f3e80b7 100644 --- a/fs/autofs4/symlink.c +++ b/fs/autofs4/symlink.c @@ -1,4 +1,4 @@ -/* -*- linux-c -*- --------------------------------------------------------- * +/* -*- c -*- --------------------------------------------------------------- * * * linux/fs/autofs/symlink.c * diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index b3b45fc0b..f49f213e0 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -1,4 +1,4 @@ -/* -*- linux-c -*- --------------------------------------------------------- * +/* -*- c -*- --------------------------------------------------------------- * * * linux/fs/autofs/waitq.c * @@ -45,7 +45,6 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) sbi->pipe = NULL; } - autofs4_ihash_nuke(&sbi->ihash); shrink_dcache_sb(sbi->sb); } diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 1744c5eef..2ff8ae8f2 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -79,8 +79,8 @@ struct inode_operations bad_inode_ops = * @inode: Inode to mark bad * * When an inode cannot be read due to a media or remote network - * failure this function makes the inode 'bad' and causes I/O operations - * on it to fail from this point on + * failure this function makes the inode "bad" and causes I/O operations + * on it to fail from this point on. */ void make_bad_inode(struct inode * inode) @@ -101,7 +101,7 @@ void make_bad_inode(struct inode * inode) * is_bad_inode - is an inode errored * @inode: inode to test * - * Returns true if the inode in question has been marked as bad + * Returns true if the inode in question has been marked as bad. */ int is_bad_inode(struct inode * inode) diff --git a/fs/bfs/file.c b/fs/bfs/file.c index c5ca51cda..a5d014f31 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -127,7 +127,7 @@ out: return err; } -static int bfs_writepage(struct dentry *dentry, struct page *page) +static int bfs_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page, bfs_get_block); } @@ -150,6 +150,7 @@ static int bfs_bmap(struct address_space *mapping, long block) struct address_space_operations bfs_aops = { readpage: bfs_readpage, writepage: bfs_writepage, + sync_page: block_sync_page, prepare_write: bfs_prepare_write, commit_write: generic_commit_write, bmap: bfs_bmap diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index f48a2492d..4abff232c 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -252,7 +252,6 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm) static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct exec ex; - int fd; unsigned long error; unsigned long fd_offset; unsigned long rlim; @@ -284,11 +283,14 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) return retval; /* OK, This is the point of no return */ - current->personality = PER_LINUX; - -#if defined(__sparc__) && !defined(__sparc_v9__) +#if !defined(__sparc__) + set_personality(PER_LINUX); +#else + set_personality(PER_SUNOS); +#if !defined(__sparc_v9__) memcpy(¤t->thread.core_exec, &ex, sizeof(struct exec)); #endif +#endif current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); @@ -341,12 +343,6 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) error_time2 = jiffies; } - fd = get_unused_fd(); - if (fd < 0) - return fd; - get_file(bprm->file); - fd_install(fd, bprm->file); - if ((fd_offset & ~PAGE_MASK) != 0 && (jiffies-error_time) > 5*HZ) { @@ -358,7 +354,6 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) { loff_t pos = fd_offset; - sys_close(fd); do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex), ex.a_text+ex.a_data, &pos); @@ -374,7 +369,6 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) fd_offset); if (error != N_TXTADDR(ex)) { - sys_close(fd); send_sig(SIGKILL, current, 0); return error; } @@ -383,20 +377,13 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); - sys_close(fd); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } } beyond_if: - put_exec_domain(current->exec_domain); - if (current->binfmt && current->binfmt->module) - __MOD_DEC_USE_COUNT(current->binfmt->module); - current->exec_domain = lookup_exec_domain(current->personality); - current->binfmt = &aout_format; - if (current->binfmt && current->binfmt->module) - __MOD_INC_USE_COUNT(current->binfmt->module); + set_binfmt(&aout_format); set_brk(current->mm->start_brk, current->mm->brk); diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index a12183834..788d8c0d5 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -487,10 +487,22 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) #ifdef __sparc__ if (ibcs2_interpreter) { unsigned long old_pers = current->personality; - - current->personality = PER_SVR4; + struct exec_domain *old_domain = current->exec_domain; + struct exec_domain *new_domain; + struct fs_struct *old_fs = current->fs, *new_fs; + get_exec_domain(old_domain); + atomic_inc(&old_fs->count); + + set_personality(PER_SVR4); interpreter = open_exec(elf_interpreter); + + new_domain = current->exec_domain; + new_fs = current->fs; current->personality = old_pers; + current->exec_domain = old_domain; + current->fs = old_fs; + put_exec_domain(new_domain); + put_fs_struct(new_fs); } else #endif { @@ -676,19 +688,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); - put_exec_domain(current->exec_domain); - if (current->binfmt && current->binfmt->module) - __MOD_DEC_USE_COUNT(current->binfmt->module); - current->exec_domain = lookup_exec_domain(current->personality); - current->binfmt = &elf_format; - if (current->binfmt && current->binfmt->module) - __MOD_INC_USE_COUNT(current->binfmt->module); + set_binfmt(&elf_format); -#ifndef VM_STACK_FLAGS - lock_kernel(); - current->executable = dget(bprm->file->f_dentry); - unlock_kernel(); -#endif compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; bprm->p = (unsigned long) @@ -970,7 +971,7 @@ static int writenote(struct memelfnote *men, struct file *file) #undef DUMP_SEEK #define DUMP_WRITE(addr, nr) \ - if (!dump_write(file, (addr), (nr))) \ + if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ goto end_coredump; #define DUMP_SEEK(off) \ if (!dump_seek(file, (off))) \ @@ -987,8 +988,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) int has_dumped = 0; mm_segment_t fs; int segs; + size_t size = 0; int i; - size_t size; struct vm_area_struct *vma; struct elfhdr elf; off_t offset = 0, dataoff; @@ -999,24 +1000,10 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - /* Count what's needed to dump, up to the limit of coredump size */ - segs = 0; - size = 0; - for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { - if (maydump(vma)) - { - unsigned long sz = vma->vm_end-vma->vm_start; - - if (size+sz >= limit) - break; - else - size += sz; - } + segs = current->mm->map_count; - segs++; - } #ifdef DEBUG - printk("elf_core_dump: %d segs taking %d bytes\n", segs, size); + printk("elf_core_dump: %d segs %lu limit\n", segs, limit); #endif /* Set up header */ @@ -1173,13 +1160,10 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); /* Write program headers for segments dump */ - for(vma = current->mm->mmap, i = 0; - i < segs && vma != NULL; vma = vma->vm_next) { + for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; - i++; - sz = vma->vm_end - vma->vm_start; phdr.p_type = PT_LOAD; @@ -1205,19 +1189,36 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) DUMP_SEEK(dataoff); - for(i = 0, vma = current->mm->mmap; - i < segs && vma != NULL; - vma = vma->vm_next) { - unsigned long addr = vma->vm_start; - unsigned long len = vma->vm_end - vma->vm_start; + for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + unsigned long addr; - i++; if (!maydump(vma)) continue; #ifdef DEBUG printk("elf_core_dump: writing %08lx %lx\n", addr, len); #endif - DUMP_WRITE((void *)addr, len); + for (addr = vma->vm_start; + addr < vma->vm_end; + addr += PAGE_SIZE) { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_offset(vma->vm_mm, addr); + pmd = pmd_alloc(pgd, addr); + + if (!pmd) + goto end_coredump; + pte = pte_alloc(pmd, addr); + if (!pte) + goto end_coredump; + if (!pte_present(*pte) && + pte_none(*pte)) { + DUMP_SEEK (file->f_pos + PAGE_SIZE); + } else { + DUMP_WRITE((void*)addr, PAGE_SIZE); + } + } } if ((off_t) file->f_pos != offset) { diff --git a/fs/block_dev.c b/fs/block_dev.c index c455a735d..a170bb2b6 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -313,7 +313,7 @@ ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos) * since the vma has no handle. */ -static int block_fsync(struct file *filp, struct dentry *dentry) +int block_fsync(struct file *filp, struct dentry *dentry) { return fsync_dev(dentry->d_inode->i_rdev); } @@ -650,7 +650,7 @@ int blkdev_put(struct block_device *bdev, int kind) return ret; } -static int blkdev_close(struct inode * inode, struct file * filp) +int blkdev_close(struct inode * inode, struct file * filp) { return blkdev_put(inode->i_bdev, BDEV_FILE); } diff --git a/fs/buffer.c b/fs/buffer.c index 26580ee0d..4e9fa9015 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -28,6 +28,7 @@ /* async buffer flushing, 1999 Andrea Arcangeli <andrea@suse.de> */ +#include <linux/config.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/malloc.h> @@ -1755,8 +1756,6 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate) kiobuf = bh->b_kiobuf; unlock_buffer(bh); - - kiobuf = bh->b_kiobuf; end_kio_request(kiobuf, uptodate); } @@ -2192,7 +2191,7 @@ busy_buffer_page: void show_buffers(void) { -#ifdef __SMP__ +#ifdef CONFIG_SMP struct buffer_head * bh; int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0; int protected = 0; @@ -2203,7 +2202,7 @@ void show_buffers(void) printk("Buffer memory: %6dkB\n", atomic_read(&buffermem_pages) << (PAGE_SHIFT-10)); -#ifdef __SMP__ /* trylock does nothing on UP and so we could deadlock */ +#ifdef CONFIG_SMP /* trylock does nothing on UP and so we could deadlock */ if (!spin_trylock(&lru_list_lock)) return; for(nlist = 0; nlist < NR_LIST; nlist++) { @@ -2416,6 +2415,12 @@ static int sync_old_buffers(void) return 0; } +int block_sync_page(struct page *page) +{ + run_task_queue(&tq_disk); + return 0; +} + /* This is the interface to bdflush. As we get more sophisticated, we can * pass tuning parameters to this "process", to adjust how it behaves. * We would want to verify each parameter, however, to make sure that it diff --git a/fs/cramfs/inflate/adler32.c b/fs/cramfs/inflate/adler32.c index 16cf9a703..813f89cd6 100644 --- a/fs/cramfs/inflate/adler32.c +++ b/fs/cramfs/inflate/adler32.c @@ -18,7 +18,7 @@ #define DO16(buf) DO8(buf,0); DO8(buf,8); /* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) +uLong ZEXPORT cramfs_adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; diff --git a/fs/cramfs/inflate/infblock.c b/fs/cramfs/inflate/infblock.c index b6cc1fc86..3cb241d71 100644 --- a/fs/cramfs/inflate/infblock.c +++ b/fs/cramfs/inflate/infblock.c @@ -65,7 +65,7 @@ local const uInt border[] = { /* Order of the bit length code lengths */ */ -void inflate_blocks_reset(s, z, c) +void cramfs_inflate_blocks_reset(s, z, c) inflate_blocks_statef *s; z_streamp z; uLongf *c; @@ -73,7 +73,7 @@ uLongf *c; if (c != Z_NULL) *c = s->check; if (s->mode == CODES) - inflate_codes_free(s->sub.decode.codes, z); + cramfs_inflate_codes_free(s->sub.decode.codes, z); s->mode = TYPE; s->bitk = 0; s->bitb = 0; @@ -83,7 +83,7 @@ uLongf *c; } -inflate_blocks_statef *inflate_blocks_new(z, c, w) +inflate_blocks_statef *cramfs_inflate_blocks_new(z, c, w) z_streamp z; check_func c; uInt w; @@ -99,12 +99,12 @@ uInt w; s->end = s->window + w; s->checkfn = c; s->mode = TYPE; - inflate_blocks_reset(s, z, Z_NULL); + cramfs_inflate_blocks_reset(s, z, Z_NULL); return s; } -int inflate_blocks(s, z, r) +int cramfs_inflate_blocks(s, z, r) inflate_blocks_statef *s; z_streamp z; int r; @@ -140,8 +140,8 @@ int r; uInt bl, bd; inflate_huft *tl, *td; - inflate_trees_fixed(&bl, &bd, &tl, &td, z); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + cramfs_inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = cramfs_inflate_codes_new(bl, bd, tl, td, z); if (s->sub.decode.codes == Z_NULL) { r = Z_MEM_ERROR; @@ -219,7 +219,7 @@ int r; while (s->sub.trees.index < 19) s->sub.trees.blens[border[s->sub.trees.index++]] = 0; s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + t = cramfs_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, &s->sub.trees.tb, s->hufts, z); if (t != Z_OK) { @@ -239,7 +239,7 @@ int r; t = s->sub.trees.bb; NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + h = s->sub.trees.tb + ((uInt)b & cramfs_inflate_mask[t]); t = h->bits; c = h->base; if (c < 16) @@ -253,7 +253,7 @@ int r; j = c == 18 ? 11 : 3; NEEDBITS(t + i) DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; + j += (uInt)b & cramfs_inflate_mask[i]; DUMPBITS(i) i = s->sub.trees.index; t = s->sub.trees.table; @@ -281,7 +281,7 @@ int r; bl = 9; /* must be <= 9 for lookahead assumptions */ bd = 6; /* must be <= 9 for lookahead assumptions */ t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + t = cramfs_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), s->sub.trees.blens, &bl, &bd, &tl, &td, s->hufts, z); if (t != Z_OK) @@ -291,7 +291,7 @@ int r; r = t; LEAVE } - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + if ((c = cramfs_inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) { r = Z_MEM_ERROR; LEAVE @@ -301,10 +301,10 @@ int r; s->mode = CODES; case CODES: UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); + if ((r = cramfs_inflate_codes(s, z, r)) != Z_STREAM_END) + return cramfs_inflate_flush(s, z, r); r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); + cramfs_inflate_codes_free(s->sub.decode.codes, z); LOAD if (!s->last) { @@ -330,16 +330,16 @@ int r; } -int inflate_blocks_free(s, z) +int cramfs_inflate_blocks_free(s, z) inflate_blocks_statef *s; z_streamp z; { - inflate_blocks_reset(s, z, Z_NULL); + cramfs_inflate_blocks_reset(s, z, Z_NULL); return Z_OK; } -void inflate_set_dictionary(s, d, n) +void cramfs_inflate_set_dictionary(s, d, n) inflate_blocks_statef *s; const Bytef *d; uInt n; diff --git a/fs/cramfs/inflate/infblock.h b/fs/cramfs/inflate/infblock.h index bd25c8075..bb13ad6ff 100644 --- a/fs/cramfs/inflate/infblock.h +++ b/fs/cramfs/inflate/infblock.h @@ -11,26 +11,26 @@ struct inflate_blocks_state; typedef struct inflate_blocks_state FAR inflate_blocks_statef; -extern inflate_blocks_statef * inflate_blocks_new OF(( +extern inflate_blocks_statef * cramfs_inflate_blocks_new OF(( z_streamp z, check_func c, /* check function */ uInt w)); /* window size */ -extern int inflate_blocks OF(( +extern int cramfs_inflate_blocks OF(( inflate_blocks_statef *, z_streamp , int)); /* initial return code */ -extern void inflate_blocks_reset OF(( +extern void cramfs_inflate_blocks_reset OF(( inflate_blocks_statef *, z_streamp , uLongf *)); /* check value on output */ -extern int inflate_blocks_free OF(( +extern int cramfs_inflate_blocks_free OF(( inflate_blocks_statef *, z_streamp)); -extern void inflate_set_dictionary OF(( +extern void cramfs_inflate_set_dictionary OF(( inflate_blocks_statef *s, const Bytef *d, /* dictionary */ uInt n)); /* dictionary length */ diff --git a/fs/cramfs/inflate/infcodes.c b/fs/cramfs/inflate/infcodes.c index ea7f6aba8..77762ff63 100644 --- a/fs/cramfs/inflate/infcodes.c +++ b/fs/cramfs/inflate/infcodes.c @@ -56,7 +56,7 @@ struct inflate_codes_state { }; -inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +inflate_codes_statef *cramfs_inflate_codes_new(bl, bd, tl, td, z) uInt bl, bd; inflate_huft *tl; inflate_huft *td; /* need separate declaration for Borland C++ */ @@ -77,7 +77,7 @@ z_streamp z; } -int inflate_codes(s, z, r) +int cramfs_inflate_codes(s, z, r) inflate_blocks_statef *s; z_streamp z; int r; @@ -105,7 +105,7 @@ int r; if (m >= 258 && n >= 10) { UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + r = cramfs_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); LOAD if (r != Z_OK) { @@ -120,7 +120,7 @@ int r; case LEN: /* i: get length/literal/eob next */ j = c->sub.code.need; NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + t = c->sub.code.tree + ((uInt)b & cramfs_inflate_mask[j]); DUMPBITS(t->bits) e = (uInt)(t->exop); if (e == 0) /* literal */ @@ -154,7 +154,7 @@ int r; case LENEXT: /* i: getting length extra (have base) */ j = c->sub.copy.get; NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; + c->len += (uInt)b & cramfs_inflate_mask[j]; DUMPBITS(j) c->sub.code.need = c->dbits; c->sub.code.tree = c->dtree; @@ -162,7 +162,7 @@ int r; case DIST: /* i: get distance next */ j = c->sub.code.need; NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + t = c->sub.code.tree + ((uInt)b & cramfs_inflate_mask[j]); DUMPBITS(t->bits) e = (uInt)(t->exop); if (e & 16) /* distance */ @@ -185,7 +185,7 @@ int r; case DISTEXT: /* i: getting distance extra */ j = c->sub.copy.get; NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; + c->sub.copy.dist += (uInt)b & cramfs_inflate_mask[j]; DUMPBITS(j) c->mode = COPY; case COPY: /* o: copying bytes in window, waiting for space */ @@ -240,7 +240,7 @@ int r; } -void inflate_codes_free(c, z) +void cramfs_inflate_codes_free(c, z) inflate_codes_statef *c; z_streamp z; { diff --git a/fs/cramfs/inflate/infcodes.h b/fs/cramfs/inflate/infcodes.h index 6c750d896..283b29201 100644 --- a/fs/cramfs/inflate/infcodes.h +++ b/fs/cramfs/inflate/infcodes.h @@ -11,17 +11,17 @@ struct inflate_codes_state; typedef struct inflate_codes_state FAR inflate_codes_statef; -extern inflate_codes_statef *inflate_codes_new OF(( +extern inflate_codes_statef *cramfs_inflate_codes_new OF(( uInt, uInt, inflate_huft *, inflate_huft *, z_streamp )); -extern int inflate_codes OF(( +extern int cramfs_inflate_codes OF(( inflate_blocks_statef *, z_streamp , int)); -extern void inflate_codes_free OF(( +extern void cramfs_inflate_codes_free OF(( inflate_codes_statef *, z_streamp )); diff --git a/fs/cramfs/inflate/inffast.c b/fs/cramfs/inflate/inffast.c index 5da2cd0a9..00995d4cd 100644 --- a/fs/cramfs/inflate/inffast.c +++ b/fs/cramfs/inflate/inffast.c @@ -25,7 +25,7 @@ struct inflate_codes_state {int dummy;}; /* for buggy compilers */ at least ten. The ten bytes are six bytes for the longest length/ distance pair plus four bytes for overloading the bit buffer. */ -int inflate_fast(bl, bd, tl, td, s, z) +int cramfs_inflate_fast(bl, bd, tl, td, s, z) uInt bl, bd; inflate_huft *tl; inflate_huft *td; /* need separate declaration for Borland C++ */ @@ -50,8 +50,8 @@ z_streamp z; LOAD /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; + ml = cramfs_inflate_mask[bl]; + md = cramfs_inflate_mask[bd]; /* do until not enough input or output space for fast loop */ do { /* assume called with m >= 258 && n >= 10 */ @@ -70,7 +70,7 @@ z_streamp z; { /* get extra bits for length */ e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); + c = t->base + ((uInt)b & cramfs_inflate_mask[e]); DUMPBITS(e) /* decode distance base of block to copy */ @@ -83,7 +83,7 @@ z_streamp z; /* get extra bits to add to distance base */ e &= 15; GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); + d = t->base + ((uInt)b & cramfs_inflate_mask[e]); DUMPBITS(e) /* do the copy */ @@ -115,7 +115,7 @@ z_streamp z; else if ((e & 64) == 0) { t += t->base; - e = (t += ((uInt)b & inflate_mask[e]))->exop; + e = (t += ((uInt)b & cramfs_inflate_mask[e]))->exop; } else { @@ -130,7 +130,7 @@ z_streamp z; if ((e & 64) == 0) { t += t->base; - if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + if ((e = (t += ((uInt)b & cramfs_inflate_mask[e]))->exop) == 0) { DUMPBITS(t->bits) *q++ = (Byte)t->base; diff --git a/fs/cramfs/inflate/inffast.h b/fs/cramfs/inflate/inffast.h index 8facec553..9d7697589 100644 --- a/fs/cramfs/inflate/inffast.h +++ b/fs/cramfs/inflate/inffast.h @@ -8,7 +8,7 @@ subject to change. Applications should only use zlib.h. */ -extern int inflate_fast OF(( +extern int cramfs_inflate_fast OF(( uInt, uInt, inflate_huft *, diff --git a/fs/cramfs/inflate/inflate.c b/fs/cramfs/inflate/inflate.c index c5b7a0c44..b5bfb67bf 100644 --- a/fs/cramfs/inflate/inflate.c +++ b/fs/cramfs/inflate/inflate.c @@ -50,7 +50,7 @@ struct internal_state { }; -int ZEXPORT inflateReset(z) +int ZEXPORT cramfs_inflateReset(z) z_streamp z; { if (z == Z_NULL || z->state == Z_NULL) @@ -58,24 +58,24 @@ z_streamp z; z->total_in = z->total_out = 0; z->msg = Z_NULL; z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, Z_NULL); + cramfs_inflate_blocks_reset(z->state->blocks, z, Z_NULL); return Z_OK; } -int ZEXPORT inflateEnd(z) +int ZEXPORT cramfs_inflateEnd(z) z_streamp z; { if (z == Z_NULL || z->state == Z_NULL) return Z_STREAM_ERROR; if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z); + cramfs_inflate_blocks_free(z->state->blocks, z); z->state = Z_NULL; return Z_OK; } -int ZEXPORT inflateInit2_(z, w, version, stream_size) +int ZEXPORT cramfs_inflateInit2_(z, w, version, stream_size) z_streamp z; int w; const char *version; @@ -105,39 +105,39 @@ int stream_size; /* set window size */ if (w < 8 || w > 15) { - inflateEnd(z); + cramfs_inflateEnd(z); return Z_STREAM_ERROR; } z->state->wbits = (uInt)w; /* create inflate_blocks state */ if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + cramfs_inflate_blocks_new(z, z->state->nowrap ? Z_NULL : cramfs_adler32, (uInt)1 << w)) == Z_NULL) { - inflateEnd(z); + cramfs_inflateEnd(z); return Z_MEM_ERROR; } /* reset state */ - inflateReset(z); + cramfs_inflateReset(z); return Z_OK; } -int ZEXPORT inflateInit_(z, version, stream_size) +int ZEXPORT cramfs_inflateInit_(z, version, stream_size) z_streamp z; const char *version; int stream_size; { - return inflateInit2_(z, DEF_WBITS, version, stream_size); + return cramfs_inflateInit2_(z, DEF_WBITS, version, stream_size); } #define NEEDBYTE {if(z->avail_in==0)return r;r=f;} #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) -int ZEXPORT inflate(z, f) +int ZEXPORT cramfs_inflate(z, f) z_streamp z; int f; { @@ -207,7 +207,7 @@ int f; z->state->sub.marker = 0; /* can try inflateSync */ return Z_STREAM_ERROR; case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); + r = cramfs_inflate_blocks(z->state->blocks, z, r); if (r == Z_DATA_ERROR) { z->state->mode = BAD; @@ -219,7 +219,7 @@ int f; if (r != Z_STREAM_END) return r; r = f; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + cramfs_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); if (z->state->nowrap) { z->state->mode = DONE; @@ -263,7 +263,7 @@ int f; } -int ZEXPORT inflateSync(z) +int ZEXPORT cramfs_inflateSync(z) z_streamp z; { uInt n; /* number of bytes to look at */ @@ -307,7 +307,7 @@ z_streamp z; if (m != 4) return Z_DATA_ERROR; r = z->total_in; w = z->total_out; - inflateReset(z); + cramfs_inflateReset(z); z->total_in = r; z->total_out = w; z->state->mode = BLOCKS; return Z_OK; @@ -321,7 +321,7 @@ z_streamp z; * decompressing, PPP checks that at the end of input packet, inflate is * waiting for these length bytes. */ -int ZEXPORT inflateSyncPoint(z) +int ZEXPORT cramfs_inflateSyncPoint(z) z_streamp z; { if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) diff --git a/fs/cramfs/inflate/inftrees.c b/fs/cramfs/inflate/inftrees.c index 250c8833e..b71a0c578 100644 --- a/fs/cramfs/inflate/inftrees.c +++ b/fs/cramfs/inflate/inftrees.c @@ -6,7 +6,7 @@ #include "zutil.h" #include "inftrees.h" -const char inflate_copyright[] = +static const char inflate_copyright[] = " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome @@ -287,7 +287,7 @@ uIntf *v; /* working area: values in order of bit length */ } -int inflate_trees_bits(c, bb, tb, hp, z) +int cramfs_inflate_trees_bits(c, bb, tb, hp, z) uIntf *c; /* 19 code lengths */ uIntf *bb; /* bits tree desired/actual depth */ inflate_huft * FAR *tb; /* bits tree result */ @@ -312,7 +312,7 @@ z_streamp z; /* for messages */ return r; } -int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) +int cramfs_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) uInt nl; /* number of literal/length codes */ uInt nd; /* number of distance codes */ uIntf *c; /* that many (total) code lengths */ @@ -377,7 +377,7 @@ z_streamp z; /* for messages */ #include "inffixed.h" -int inflate_trees_fixed(bl, bd, tl, td, z) +int cramfs_inflate_trees_fixed(bl, bd, tl, td, z) uIntf *bl; /* literal desired/actual bit depth */ uIntf *bd; /* distance desired/actual bit depth */ inflate_huft * FAR *tl; /* literal/length tree result */ diff --git a/fs/cramfs/inflate/inftrees.h b/fs/cramfs/inflate/inftrees.h index 85853e097..5d5296985 100644 --- a/fs/cramfs/inflate/inftrees.h +++ b/fs/cramfs/inflate/inftrees.h @@ -32,14 +32,14 @@ struct inflate_huft_s { value below is more than safe. */ #define MANY 1440 -extern int inflate_trees_bits OF(( +extern int cramfs_inflate_trees_bits OF(( uIntf *, /* 19 code lengths */ uIntf *, /* bits tree desired/actual depth */ inflate_huft * FAR *, /* bits tree result */ inflate_huft *, /* space for trees */ z_streamp)); /* for messages */ -extern int inflate_trees_dynamic OF(( +extern int cramfs_inflate_trees_dynamic OF(( uInt, /* number of literal/length codes */ uInt, /* number of distance codes */ uIntf *, /* that many (total) code lengths */ @@ -50,7 +50,7 @@ extern int inflate_trees_dynamic OF(( inflate_huft *, /* space for trees */ z_streamp)); /* for messages */ -extern int inflate_trees_fixed OF(( +extern int cramfs_inflate_trees_fixed OF(( uIntf *, /* literal desired/actual bit depth */ uIntf *, /* distance desired/actual bit depth */ inflate_huft * FAR *, /* literal/length tree result */ diff --git a/fs/cramfs/inflate/infutil.c b/fs/cramfs/inflate/infutil.c index 23b6d96d0..3fffc1059 100644 --- a/fs/cramfs/inflate/infutil.c +++ b/fs/cramfs/inflate/infutil.c @@ -12,7 +12,7 @@ struct inflate_codes_state {int dummy;}; /* for buggy compilers */ /* And'ing with mask[n] masks the lower n bits */ -uInt inflate_mask[17] = { +uInt cramfs_inflate_mask[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff @@ -20,7 +20,7 @@ uInt inflate_mask[17] = { /* copy as much as possible from the sliding window to the output area */ -int inflate_flush(s, z, r) +int cramfs_inflate_flush(s, z, r) inflate_blocks_statef *s; z_streamp z; int r; diff --git a/fs/cramfs/inflate/infutil.h b/fs/cramfs/inflate/infutil.h index 99d1135d0..4abbb65f5 100644 --- a/fs/cramfs/inflate/infutil.h +++ b/fs/cramfs/inflate/infutil.h @@ -67,7 +67,7 @@ struct inflate_blocks_state { #define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} #define UPDOUT {s->write=q;} #define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} +#define LEAVE {UPDATE return cramfs_inflate_flush(s,z,r);} /* get bytes and bits */ #define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} #define NEEDBYTE {if(n)r=Z_OK;else LEAVE} @@ -78,17 +78,17 @@ struct inflate_blocks_state { #define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q) #define LOADOUT {q=s->write;m=(uInt)WAVAIL;} #define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define FLUSH {UPDOUT r=cramfs_inflate_flush(s,z,r); LOADOUT} #define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} #define OUTBYTE(a) {*q++=(Byte)(a);m--;} /* load local pointers */ #define LOAD {LOADIN LOADOUT} /* masks for lower bits (size given to avoid silly warnings with Visual C++) */ -extern uInt inflate_mask[17]; +extern uInt cramfs_inflate_mask[17]; /* copy as much as possible from the sliding window to the output area */ -extern int inflate_flush OF(( +extern int cramfs_inflate_flush OF(( inflate_blocks_statef *, z_streamp , int)); diff --git a/fs/cramfs/inflate/uncompr.c b/fs/cramfs/inflate/uncompr.c index 45eb47b72..864eeb27f 100644 --- a/fs/cramfs/inflate/uncompr.c +++ b/fs/cramfs/inflate/uncompr.c @@ -40,16 +40,16 @@ int ZEXPORT uncompress (dest, destLen, source, sourceLen) stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - err = inflateInit(&stream); + err = cramfs_inflateInit(&stream); if (err != Z_OK) return err; - err = inflate(&stream, Z_FINISH); + err = cramfs_inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { - inflateEnd(&stream); + cramfs_inflateEnd(&stream); return err == Z_OK ? Z_BUF_ERROR : err; } *destLen = stream.total_out; - err = inflateEnd(&stream); + err = cramfs_inflateEnd(&stream); return err; } diff --git a/fs/cramfs/inflate/zlib.h b/fs/cramfs/inflate/zlib.h index f35937912..d68c523f1 100644 --- a/fs/cramfs/inflate/zlib.h +++ b/fs/cramfs/inflate/zlib.h @@ -291,7 +291,7 @@ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); +ZEXTERN int ZEXPORT cramfs_inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by @@ -311,7 +311,7 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); */ -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT cramfs_inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may some @@ -380,7 +380,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); */ -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT cramfs_inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any @@ -569,7 +569,7 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflate(). */ -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +ZEXTERN int ZEXPORT cramfs_inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a full flush point (see above the description of deflate with Z_FULL_FLUSH) can be found, or until all @@ -584,7 +584,7 @@ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); until success or end of the input data. */ -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT cramfs_inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. @@ -818,7 +818,7 @@ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); compression library. */ -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +ZEXTERN uLong ZEXPORT cramfs_adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and @@ -859,23 +859,23 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, +ZEXTERN int ZEXPORT cramfs_inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, +ZEXTERN int ZEXPORT cramfs_inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); #define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define cramfs_inflateInit(strm) \ + cramfs_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + cramfs_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) #if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) @@ -883,7 +883,7 @@ ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, #endif ZEXTERN const char * ZEXPORT zError OF((int err)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN int ZEXPORT cramfs_inflateSyncPoint OF((z_streamp z)); ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); #ifdef __cplusplus diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c index 7a34b2b30..d946b56e7 100644 --- a/fs/cramfs/uncompress.c +++ b/fs/cramfs/uncompress.c @@ -33,14 +33,14 @@ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen) stream.next_out = dst; stream.avail_out = dstlen; - err = inflateReset(&stream); + err = cramfs_inflateReset(&stream); if (err != Z_OK) { - printk("inflateReset error %d\n", err); - inflateEnd(&stream); - inflateInit(&stream); + printk("cramfs_inflateReset error %d\n", err); + cramfs_inflateEnd(&stream); + cramfs_inflateInit(&stream); } - err = inflate(&stream, Z_FINISH); + err = cramfs_inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) goto err; return stream.total_out; @@ -56,7 +56,7 @@ int cramfs_uncompress_init(void) if (!initialized++) { stream.next_in = NULL; stream.avail_in = 0; - inflateInit(&stream); + cramfs_inflateInit(&stream); } return 0; } @@ -64,6 +64,6 @@ int cramfs_uncompress_init(void) int cramfs_uncompress_exit(void) { if (!--initialized) - inflateEnd(&stream); + cramfs_inflateEnd(&stream); return 0; } diff --git a/fs/dcache.c b/fs/dcache.c index 24e2f2568..3caf950eb 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <linux/cache.h> #include <asm/uaccess.h> @@ -40,11 +41,12 @@ kmem_cache_t *dentry_cache; * This hash-function tries to avoid losing too many bits of hash * information, yet avoid using a prime hash-size or similar. */ -#define D_HASHBITS 14 -#define D_HASHSIZE (1UL << D_HASHBITS) -#define D_HASHMASK (D_HASHSIZE-1) +#define D_HASHBITS d_hash_shift +#define D_HASHMASK d_hash_mask -static struct list_head dentry_hashtable[D_HASHSIZE]; +static unsigned int d_hash_mask; +static unsigned int d_hash_shift; +static struct list_head *dentry_hashtable; static LIST_HEAD(dentry_unused); struct { @@ -83,7 +85,7 @@ static inline void dentry_iput(struct dentry * dentry) } /* - * dput + * This is dput * * This is complicated by the fact that we do not want to put * dentries that are no longer on any hash chain on the unused @@ -534,7 +536,7 @@ int shrink_dcache_memory(int priority, unsigned int gfp_mask, zone_t * zone) * @parent: parent of entry to allocate * @name: qstr of the name * - * Allocates a dentry. It returns NULL if there is insufficient memory + * Allocates a dentry. It returns %NULL if there is insufficient memory * available. On a success the dentry is returned. The name passed in is * copied and the copy passed in may be reused after this call. */ @@ -590,7 +592,7 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name) /** * d_instantiate - fill in inode information for a dentry * @entry: dentry to complete - * @inode: inode to attacheto this dentry + * @inode: inode to attach to this dentry * * Fill in inode information in the entry. * @@ -599,7 +601,7 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name) * * NOTE! This assumes that the inode count has been incremented * (or otherwise set) by the caller to indicate that it is now - * in use by the dcache.. + * in use by the dcache. */ void d_instantiate(struct dentry *entry, struct inode * inode) @@ -613,9 +615,9 @@ void d_instantiate(struct dentry *entry, struct inode * inode) * d_alloc_root - allocate root dentry * @root_inode: inode to allocate the root for * - * Allocate a root ('/') dentry for the inode given. The inode is - * instantiated and returned. NULL is returned if there is insufficient - * memory or the inode passed is NULL. + * Allocate a root ("/") dentry for the inode given. The inode is + * instantiated and returned. %NULL is returned if there is insufficient + * memory or the inode passed is %NULL. */ struct dentry * d_alloc_root(struct inode * root_inode) @@ -635,7 +637,7 @@ struct dentry * d_alloc_root(struct inode * root_inode) static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash) { - hash += (unsigned long) parent; + hash += (unsigned long) parent / L1_CACHE_BYTES; hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2); return dentry_hashtable + (hash & D_HASHMASK); } @@ -648,7 +650,7 @@ static inline struct list_head * d_hash(struct dentry * parent, unsigned long ha * Searches the children of the parent dentry for the name in question. If * the dentry is found its reference count is incremented and the dentry * is returned. The caller must use d_put to free the entry when it has - * finished using it. NULL is returned on failure. + * finished using it. %NULL is returned on failure. */ struct dentry * d_lookup(struct dentry * parent, struct qstr * name) @@ -780,7 +782,7 @@ void d_delete(struct dentry * dentry) * d_rehash - add an entry back to the hash * @entry: dentry to add to the hash * - * Adds a dentry to the hash according to its name + * Adds a dentry to the hash according to its name. */ void d_rehash(struct dentry * entry) @@ -881,11 +883,11 @@ void d_move(struct dentry * dentry, struct dentry * target) * @buffer: buffer to return value in * @buflen: buffer length * - * Convert a dentry into an ascii path name. If the entry has been deleted - * the string ' (deleted)' is appended. Note that this is ambiguous. Returns + * Convert a dentry into an ASCII path name. If the entry has been deleted + * the string " (deleted)" is appended. Note that this is ambiguous. Returns * the buffer. * - * "buflen" should be PAGE_SIZE or more. + * "buflen" should be %PAGE_SIZE or more. */ char * __d_path(struct dentry *dentry, struct vfsmount *vfsmnt, struct dentry *root, struct vfsmount *rootmnt, @@ -1054,10 +1056,12 @@ out: return ino; } -void __init dcache_init(void) +void __init dcache_init(unsigned long mempages) { + struct list_head *d; + unsigned long order; + unsigned int nr_hash; int i; - struct list_head *d = dentry_hashtable; /* * A constructor could be added for stable state like the lists, @@ -1075,7 +1079,34 @@ void __init dcache_init(void) if (!dentry_cache) panic("Cannot create dentry cache"); - i = D_HASHSIZE; + mempages >>= (13 - PAGE_SHIFT); + mempages *= sizeof(struct list_head); + for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++) + ; + + do { + unsigned long tmp; + + nr_hash = (1UL << order) * PAGE_SIZE / + sizeof(struct list_head); + d_hash_mask = (nr_hash - 1); + + tmp = nr_hash; + d_hash_shift = 0; + while ((tmp >>= 1UL) != 0UL) + d_hash_shift++; + + dentry_hashtable = (struct list_head *) + __get_free_pages(GFP_ATOMIC, order); + } while (dentry_hashtable == NULL && --order >= 0); + + if (!dentry_hashtable) + panic("Failed to allocate dcache hash table\n"); + + printk("VFS: DCACHE hash table configured to %d entries\n", nr_hash); + + d = dentry_hashtable; + i = nr_hash; do { INIT_LIST_HEAD(d); d++; diff --git a/fs/devfs/base.c b/fs/devfs/base.c index eb38eff34..b934ff9b9 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -432,6 +432,17 @@ <devfs_readdir>. Work sponsored by SGI. v0.93 + 20000413 Richard Gooch <rgooch@atnf.csiro.au> + Set inode->i_size to correct size for symlinks. + 20000414 Richard Gooch <rgooch@atnf.csiro.au> + Only give lookup() method to directories to comply with new VFS + assumptions. + Work sponsored by SGI. + 20000415 Richard Gooch <rgooch@atnf.csiro.au> + Remove unnecessary tests in symlink methods. + Don't kill existing block ops in <devfs_read_inode>. + Work sponsored by SGI. + v0.94 */ #include <linux/types.h> #include <linux/errno.h> @@ -466,7 +477,7 @@ #include <asm/bitops.h> #include <asm/atomic.h> -#define DEVFS_VERSION "0.93 (20000306)" +#define DEVFS_VERSION "0.94 (20000415)" #ifndef DEVFS_NAME # define DEVFS_NAME "devfs" @@ -679,7 +690,9 @@ static unsigned int devfs_debug_init __initdata = DEBUG_NONE; static unsigned int devfs_debug = DEBUG_NONE; # endif #endif -static unsigned int boot_options = OPTION_NONE; + +/* by default, we do not mount devfs on bootup */ +static unsigned int boot_options = OPTION_NOMOUNT; /* Forward function declarations */ static struct devfs_entry *search_for_entry (struct devfs_entry *dir, @@ -1916,6 +1929,11 @@ SETUP_STATIC int __init devfs_setup (char *str) boot_options |= OPTION_ONLY; str += 4; } + else if (strncmp (str, "mount", 5) == 0) + { + boot_options &= ~OPTION_NOMOUNT; + str += 5; + } else if (strncmp (str, "nomount", 7) == 0) { boot_options |= OPTION_NOMOUNT; @@ -2185,6 +2203,7 @@ static int get_removable_partition (struct devfs_entry *dir, const char *name, /* Superblock operations follow */ static struct inode_operations devfs_iops; +static struct inode_operations devfs_dir_iops; static struct file_operations devfs_fops; static struct inode_operations devfs_symlink_iops; @@ -2208,28 +2227,33 @@ static void devfs_read_inode (struct inode *inode) inode->i_blocks = 0; inode->i_blksize = 1024; inode->i_op = &devfs_iops; + inode->i_fop = &devfs_fops; inode->i_rdev = NODEV; - if ( S_ISCHR (di->mode) ) { + if ( S_ISCHR (di->mode) ) + { inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major, di->de->u.fcb.u.device.minor); - inode->i_fop = &devfs_fops; - } else if ( S_ISBLK (di->mode) ) { + } + else if ( S_ISBLK (di->mode) ) + { inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major, di->de->u.fcb.u.device.minor); inode->i_bdev = bdget (inode->i_rdev); - if (inode->i_bdev) inode->i_bdev->bd_op = di->de->u.fcb.ops; + if (inode->i_bdev) + { + if (!inode->i_bdev->bd_op && di->de->u.fcb.ops) + inode->i_bdev->bd_op = di->de->u.fcb.ops; + } else printk ("%s: read_inode(%d): no block device from bdget()\n", DEVFS_NAME, (int) inode->i_ino); - inode->i_fop = &devfs_fops; - } else if ( S_ISFIFO (di->mode) ) { - inode->i_fop = &def_fifo_fops; - } else if ( S_ISREG (di->mode) ) { - inode->i_size = di->de->u.fcb.u.file.size; - inode->i_fop = &devfs_fops; - } else if (S_ISLNK(di->mode)) { + } + else if ( S_ISFIFO (di->mode) ) inode->i_fop = &def_fifo_fops; + else if ( S_ISREG (di->mode) ) inode->i_size = di->de->u.fcb.u.file.size; + else if ( S_ISDIR (di->mode) ) inode->i_op = &devfs_dir_iops; + else if ( S_ISLNK (di->mode) ) + { inode->i_op = &devfs_symlink_iops; - } else { - inode->i_fop = &devfs_fops; + inode->i_size = di->de->u.symlink.length; } inode->i_mode = di->mode; inode->i_uid = di->uid; @@ -2358,7 +2382,7 @@ static struct inode *get_vfs_inode (struct super_block *sb, /* File operations for device entries follow */ -static int devfs_read (struct file *file, char *buf, size_t len, loff_t *ppos) +static ssize_t devfs_read (struct file *file, char *buf, size_t len, loff_t *ppos) { if ( S_ISDIR (file->f_dentry->d_inode->i_mode) ) return -EISDIR; return -EINVAL; @@ -2747,7 +2771,7 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) de = search_for_entry_in_dir (parent, dentry->d_name.name, dentry->d_name.len, FALSE); } - if ( (de == NULL) || (!de->registered) ) + if ( (de == NULL) || !de->registered ) { /* Try with devfsd. For any kind of failure, leave a negative dentry so someone else can deal with it (in the case where the sysadmin @@ -3083,41 +3107,46 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode, static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen) { - struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode); - char *name = ERR_PTR(-ENOENT); + struct devfs_inode *di = get_devfs_inode_from_vfs_inode (dentry->d_inode); - if (di && di->de->registered) - name = di->de->u.symlink.linkname; - return vfs_readlink(dentry, buffer, buflen, name); + return vfs_readlink (dentry, buffer, buflen, di->de->u.symlink.linkname); } /* End Function devfs_readlink */ static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd) { - struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode); - char *name = ERR_PTR(-ENOENT); + struct devfs_inode *di = get_devfs_inode_from_vfs_inode (dentry->d_inode); - if (di && di->de->registered) - name = di->de->u.symlink.linkname; - return vfs_follow_link(nd, name); + return vfs_follow_link (nd, di->de->u.symlink.linkname); } /* End Function devfs_follow_link */ static struct inode_operations devfs_iops = { - lookup: devfs_lookup, - link: devfs_link, - unlink: devfs_unlink, - symlink: devfs_symlink, - mkdir: devfs_mkdir, - rmdir: devfs_rmdir, - mknod: devfs_mknod, - setattr: devfs_notify_change, + link: devfs_link, + unlink: devfs_unlink, + symlink: devfs_symlink, + mkdir: devfs_mkdir, + rmdir: devfs_rmdir, + mknod: devfs_mknod, + setattr: devfs_notify_change, +}; + +static struct inode_operations devfs_dir_iops = +{ + lookup: devfs_lookup, + link: devfs_link, + unlink: devfs_unlink, + symlink: devfs_symlink, + mkdir: devfs_mkdir, + rmdir: devfs_rmdir, + mknod: devfs_mknod, + setattr: devfs_notify_change, }; static struct inode_operations devfs_symlink_iops = { - readlink: devfs_readlink, - follow_link: devfs_follow_link, - setattr: devfs_notify_change, + readlink: devfs_readlink, + follow_link: devfs_follow_link, + setattr: devfs_notify_change, }; static struct super_block *devfs_read_super (struct super_block *sb, @@ -3179,7 +3208,7 @@ out_no_root: } /* End Function devfs_read_super */ -static DECLARE_FSTYPE(devfs_fs_type, DEVFS_NAME, devfs_read_super, 0); +static DECLARE_FSTYPE (devfs_fs_type, DEVFS_NAME, devfs_read_super, 0); /* File operations for devfsd follow */ @@ -3308,7 +3337,7 @@ static int devfsd_ioctl (struct inode *inode, struct file *file, doesn't matter who gets in first, as long as only one gets it */ if (fs_info->devfsd_task == NULL) { -#ifdef __SMP__ +#ifdef CONFIG_SMP /* Looks like no-one has it: check again and grab, with interrupts disabled */ __cli (); @@ -3318,7 +3347,7 @@ static int devfsd_ioctl (struct inode *inode, struct file *file, fs_info->devfsd_event_mask = 0; /* Temporary disable */ fs_info->devfsd_task = current; } -#ifdef __SMP__ +#ifdef CONFIG_SMP __sti (); #endif } @@ -3392,7 +3421,7 @@ void __init mount_devfs_fs (void) { int err; extern long do_sys_mount (char *dev_name, char *dir_name, - char * type, int flags, void * data); + char *type, int flags, void *data); if ( (boot_options & OPTION_NOMOUNT) ) return; err = do_sys_mount ("none", "/dev", "devfs", 0, ""); diff --git a/fs/efs/inode.c b/fs/efs/inode.c index 93edbaac6..69a5efa78 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -21,6 +21,7 @@ static int _efs_bmap(struct address_space *mapping, long block) } struct address_space_operations efs_aops = { readpage: efs_readpage, + sync_page: block_sync_page, bmap: _efs_bmap }; @@ -315,30 +315,30 @@ int setup_arg_pages(struct linux_binprm *bprm) return 0; } -/* MOUNT_REWRITE: &mnt should be passed to lookup_dentry */ struct file *open_exec(const char *name) { - struct dentry *dentry; - struct vfsmount *mnt = NULL; + struct nameidata nd; struct file *file; + int err = 0; lock_kernel(); - dentry = lookup_dentry(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE); - file = (struct file*) dentry; - if (!IS_ERR(dentry)) { + if (walk_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) + err = walk_name(name, &nd); + file = ERR_PTR(err); + if (!err) { file = ERR_PTR(-EACCES); - if (S_ISREG(dentry->d_inode->i_mode)) { - int err = permission(dentry->d_inode, MAY_EXEC); + if (S_ISREG(nd.dentry->d_inode->i_mode)) { + int err = permission(nd.dentry->d_inode, MAY_EXEC); file = ERR_PTR(err); if (!err) { - file = dentry_open(dentry, mnt, O_RDONLY); + file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); out: unlock_kernel(); return file; } } - dput(dentry); - mntput(mnt); + dput(nd.dentry); + mntput(nd.mnt); } goto out; } @@ -858,6 +858,16 @@ out: return retval; } +void set_binfmt(struct linux_binfmt *new) +{ + struct linux_binfmt *old = current->binfmt; + if (new && new->module) + __MOD_INC_USE_COUNT(new->module); + current->binfmt = new; + if (old && old->module) + __MOD_DEC_USE_COUNT(old->module); +} + int do_coredump(long signr, struct pt_regs * regs) { struct linux_binfmt * binfmt; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index dd09b95aa..e90d2bb8e 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -620,7 +620,7 @@ struct buffer_head * ext2_bread (struct inode * inode, int block, return NULL; } -static int ext2_writepage(struct dentry *dentry, struct page *page) +static int ext2_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,ext2_get_block); } @@ -639,6 +639,7 @@ static int ext2_bmap(struct address_space *mapping, long block) struct address_space_operations ext2_aops = { readpage: ext2_readpage, writepage: ext2_writepage, + sync_page: block_sync_page, prepare_write: ext2_prepare_write, commit_write: generic_commit_write, bmap: ext2_bmap diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index c5bc9471d..dff1b6841 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -218,19 +218,10 @@ int ext2_add_entry (struct inode * dir, const char * name, int namelen, struct super_block * sb; int retval; - if (!dir || !dir->i_nlink) - return -EINVAL; sb = dir->i_sb; if (!namelen) return -EINVAL; - /* - * Is this a busy deleted directory? Can't create new files if so - */ - if (dir->i_size == 0) - { - return -ENOENT; - } bh = ext2_bread (dir, 0, 0, &retval); if (!bh) return retval; @@ -284,13 +275,13 @@ int ext2_add_entry (struct inode * dir, const char * name, int namelen, de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len)); de = de1; } + de->file_type = EXT2_FT_UNKNOWN; if (inode) { de->inode = cpu_to_le32(inode->i_ino); ext2_set_de_type(dir->i_sb, de, inode->i_mode); } else de->inode = 0; de->name_len = namelen; - de->file_type = 0; memcpy (de->name, name, namelen); /* * XXX shouldn't update any times until successful diff --git a/fs/fat/file.c b/fs/fat/file.c index 4481a6df9..f82741be8 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -125,7 +125,13 @@ void fat_truncate(struct inode *inode) if (IS_IMMUTABLE(inode)) return /* -EPERM */; cluster = SECTOR_SIZE*sbi->cluster_size; - MSDOS_I(inode)->mmu_private = inode->i_size; + /* + * This protects against truncating a file bigger than it was then + * trying to write into the hole. + */ + if (MSDOS_I(inode)->mmu_private > inode->i_size) + MSDOS_I(inode)->mmu_private = inode->i_size; + fat_free(inode,(inode->i_size+(cluster-1))>>sbi->cluster_bits); MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_ctime = inode->i_mtime = CURRENT_TIME; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index a0202c66f..e7344cb20 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -729,7 +729,7 @@ static int is_exec(char *extension) return 0; } -static int fat_writepage(struct dentry *dentry, struct page *page) +static int fat_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,fat_get_block); } @@ -749,6 +749,7 @@ static int _fat_bmap(struct address_space *mapping, long block) static struct address_space_operations fat_aops = { readpage: fat_readpage, writepage: fat_writepage, + sync_page: block_sync_page, prepare_write: fat_prepare_write, commit_write: generic_commit_write, bmap: _fat_bmap diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 8c0afe0c8..09d0e0ccd 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -217,7 +217,7 @@ int hfs_notify_change_hdr(struct dentry *dentry, struct iattr * attr) return __hfs_notify_change(dentry, attr, HFS_HDR); } -static int hfs_writepage(struct dentry *dentry, struct page *page) +static int hfs_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,hfs_get_block); } @@ -237,6 +237,7 @@ static int hfs_bmap(struct address_space *mapping, long block) struct address_space_operations hfs_aops = { readpage: hfs_readpage, writepage: hfs_writepage, + sync_page: block_sync_page, prepare_write: hfs_prepare_write, commit_write: generic_commit_write, bmap: hfs_bmap diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index d8063e296..8d9567273 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -86,7 +86,7 @@ int hpfs_get_block(struct inode *inode, long iblock, struct buffer_head *bh_resu return 0; } -static int hpfs_writepage(struct dentry *dentry, struct page *page) +static int hpfs_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,hpfs_get_block); } @@ -106,6 +106,7 @@ static int _hpfs_bmap(struct address_space *mapping, long block) struct address_space_operations hpfs_aops = { readpage: hpfs_readpage, writepage: hpfs_writepage, + sync_page: block_sync_page, prepare_write: hpfs_prepare_write, commit_write: generic_commit_write, bmap: _hpfs_bmap diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index f02239eae..037c48be2 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -375,11 +375,6 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry) hpfs_unlock_2inodes(dir, inode); return -ENOTDIR; } - if (!d_unhashed(dentry)) { - hpfs_brelse4(&qbh); - hpfs_unlock_2inodes(dir, inode); - return -EBUSY; - } hpfs_count_dnodes(dir->i_sb, inode->i_hpfs_dno, NULL, NULL, &n_items); if (n_items) { hpfs_brelse4(&qbh); diff --git a/fs/inode.c b/fs/inode.c index de7267c84..9068498c2 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/quotaops.h> #include <linux/slab.h> +#include <linux/cache.h> /* * New inode.c implementation. @@ -32,9 +33,11 @@ * Inode lookup is no longer as critical as it used to be: * most of the lookups are going to be through the dcache. */ -#define HASH_BITS 14 -#define HASH_SIZE (1UL << HASH_BITS) -#define HASH_MASK (HASH_SIZE-1) +#define I_HASHBITS i_hash_shift +#define I_HASHMASK i_hash_mask + +static unsigned int i_hash_mask; +static unsigned int i_hash_shift; /* * Each inode can be on two separate lists. One is @@ -50,7 +53,7 @@ static LIST_HEAD(inode_in_use); static LIST_HEAD(inode_unused); -static struct list_head inode_hashtable[HASH_SIZE]; +static struct list_head *inode_hashtable; static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */ /* @@ -116,7 +119,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) * __mark_inode_dirty - internal function * @inode: inode to mark * - * Mark an inode as dirty. Callers should use mark_inode_dirty + * Mark an inode as dirty. Callers should use mark_inode_dirty. */ void __mark_inode_dirty(struct inode *inode) @@ -530,7 +533,7 @@ static void clean_inode(struct inode *inode) * no pre-existing information. * * On a successful return the inode pointer is returned. On a failure - * a NULL pointer is returned. The returned inode is not on any superblock + * a %NULL pointer is returned. The returned inode is not on any superblock * lists. */ @@ -617,9 +620,9 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s static inline unsigned long hash(struct super_block *sb, unsigned long i_ino) { - unsigned long tmp = i_ino | (unsigned long) sb; - tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2); - return tmp & HASH_MASK; + unsigned long tmp = i_ino | ((unsigned long) sb / L1_CACHE_BYTES); + tmp = tmp + (tmp >> I_HASHBITS) + (tmp >> I_HASHBITS*2); + return tmp & I_HASHMASK; } /* Yeah, I know about quadratic hash. Maybe, later. */ @@ -707,7 +710,7 @@ struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find * @inode: unhashed inode * * Add an inode to the inode hash for this superblock. If the inode - * has no superblock it is added to a seperate anonymous chain + * has no superblock it is added to a separate anonymous chain. */ void insert_inode_hash(struct inode *inode) @@ -724,7 +727,7 @@ void insert_inode_hash(struct inode *inode) * remove_inode_hash - remove an inode from the hash * @inode: inode to unhash * - * Remove an inode from the superblock or anonymous hash + * Remove an inode from the superblock or anonymous hash. */ void remove_inode_hash(struct inode *inode) @@ -829,9 +832,9 @@ kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count)); * * Returns the block number on the device holding the inode that * is the disk block number for the block of the file requested. - * That is asked for block 4 of inode 1 the function will return the + * That is, asked for block 4 of inode 1 the function will return the * disk block relative to the disk start that holds that block of the - * file + * file. */ int bmap(struct inode * inode, int block) @@ -845,12 +848,41 @@ int bmap(struct inode * inode, int block) /* * Initialize the hash tables. */ -void __init inode_init(void) +void __init inode_init(unsigned long mempages) { + struct list_head *head; + unsigned long order; + unsigned int nr_hash; int i; - struct list_head *head = inode_hashtable; - i = HASH_SIZE; + mempages >>= (14 - PAGE_SHIFT); + mempages *= sizeof(struct list_head); + for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++) + ; + + do { + unsigned long tmp; + + nr_hash = (1UL << order) * PAGE_SIZE / + sizeof(struct list_head); + i_hash_mask = (nr_hash - 1); + + tmp = nr_hash; + i_hash_shift = 0; + while ((tmp >>= 1UL) != 0UL) + i_hash_shift++; + + inode_hashtable = (struct list_head *) + __get_free_pages(GFP_ATOMIC, order); + } while (inode_hashtable == NULL && --order >= 0); + + if (!inode_hashtable) + panic("Failed to allocate inode hash table\n"); + + printk("VFS: INODE hash table configured to %d entries\n", nr_hash); + + head = inode_hashtable; + i = nr_hash; do { INIT_LIST_HEAD(head); head++; @@ -869,9 +901,9 @@ void __init inode_init(void) * update_atime - update the access time * @inode: inode accessed * - * Update the accessed time on an inode and mark it for writeback. + * Update the accessed time on an inode and mark it for writeback. * This function automatically handles read only file systems and media, - * as well as the noatime flag and inode specific noatime markers + * as well as the "noatime" flag and inode specific "noatime" markers. */ void update_atime (struct inode *inode) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 4ecd72cd2..a46b30714 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -991,6 +991,7 @@ static int _isofs_bmap(struct address_space *mapping, long block) } static struct address_space_operations isofs_aops = { readpage: isofs_readpage, + sync_page: block_sync_page, bmap: _isofs_bmap }; diff --git a/fs/locks.c b/fs/locks.c index 18ee63e92..015b8e87a 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -130,7 +130,7 @@ static struct file_lock *locks_init_lock(struct file_lock *, struct file_lock *); static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl); static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait); -static char *lock_get_status(struct file_lock *fl, int id, char *pfx); +static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx); static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter); static void locks_delete_block(struct file_lock *blocker, struct file_lock *waiter); @@ -1179,90 +1179,85 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait) return; } - -static char *lock_get_status(struct file_lock *fl, int id, char *pfx) +static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) { - static char temp[155]; - char *p = temp; struct inode *inode; inode = fl->fl_file->f_dentry->d_inode; - p += sprintf(p, "%d:%s ", id, pfx); + out += sprintf(out, "%d:%s ", id, pfx); if (fl->fl_flags & FL_POSIX) { - p += sprintf(p, "%6s %s ", + out += sprintf(out, "%6s %s ", (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", (IS_MANDLOCK(inode) && (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ? "MANDATORY" : "ADVISORY "); } else { - p += sprintf(p, "FLOCK ADVISORY "); + out += sprintf(out, "FLOCK ADVISORY "); } - p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE"); - p += sprintf(p, "%d %s:%ld %Ld %Ld ", + out += sprintf(out, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE"); + out += sprintf(out, "%d %s:%ld %Ld %Ld ", fl->fl_pid, kdevname(inode->i_dev), inode->i_ino, (long long)fl->fl_start, (long long)fl->fl_end); - sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n", + sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n", (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink, (long)fl->fl_next, (long)fl->fl_nextblock); - return (temp); } -static inline int copy_lock_status(char *p, char **q, off_t pos, int len, - off_t offset, int length) +static void move_lock_status(char **p, off_t* pos, off_t offset) { - off_t i; - - i = pos - offset; - if (i > 0) { - if (i >= length) { - i = len + length - i; - memcpy(*q, p, i); - *q += i; - return (0); - } - if (i < len) { - p += len - i; - } - else - i = len; - memcpy(*q, p, i); - *q += i; + int len; + len = strlen(*p); + if(*pos >= offset) { + /* the complete line is valid */ + *p += len; + *pos += len; + return; } - - return (1); + if(*pos+len > offset) { + /* use the second part of the line */ + int i = offset-*pos; + memmove(*p,*p+i,len-i); + *p += len-i; + *pos += len; + return; + } + /* discard the complete line */ + *pos += len; } int get_locks_status(char *buffer, char **start, off_t offset, int length) { struct file_lock *fl; struct file_lock *bfl; - char *p; char *q = buffer; - off_t i, len, pos = 0; + off_t pos = 0; + int i; for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) { - p = lock_get_status(fl, i, ""); - len = strlen(p); - pos += len; - if (!copy_lock_status(p, &q, pos, len, offset, length)) + lock_get_status(q, fl, i, ""); + move_lock_status(&q, &pos, offset); + + if(pos >= offset+length) goto done; + if ((bfl = fl->fl_nextblock) == NULL) continue; do { - p = lock_get_status(bfl, i, " ->"); - len = strlen(p); - pos += len; - if (!copy_lock_status(p, &q, pos, len, offset, length)) + lock_get_status(q, bfl, i, " ->"); + move_lock_status(&q, &pos, offset); + + if(pos >= offset+length) goto done; } while ((bfl = bfl->fl_nextblock) != fl); } done: - if (q != buffer) - *start = buffer; - return (q - buffer); + *start = buffer; + if(q-buffer < length) + return (q-buffer); + return length; } diff --git a/fs/minix/inode.c b/fs/minix/inode.c index a581e328a..8eb26d478 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -1006,7 +1006,7 @@ struct buffer_head * minix_bread(struct inode * inode, int block, int create) return NULL; } -static int minix_writepage(struct dentry *dentry, struct page *page) +static int minix_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,minix_get_block); } @@ -1025,6 +1025,7 @@ static int minix_bmap(struct address_space *mapping, long block) struct address_space_operations minix_aops = { readpage: minix_readpage, writepage: minix_writepage, + sync_page: block_sync_page, prepare_write: minix_prepare_write, commit_write: generic_commit_write, bmap: minix_bmap diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 211556d4a..7dc20ea7c 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -399,10 +399,6 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry) retval = -ENOENT; goto end_rmdir; } - if (!d_unhashed(dentry)) { - retval = -EBUSY; - goto end_rmdir; - } if (inode->i_nlink != 2) printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); de->inode = 0; @@ -569,9 +565,6 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, } if (S_ISDIR(old_inode->i_mode)) { if (new_inode) { - retval = -EBUSY; - if (!d_unhashed(new_dentry)) - goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_inode)) goto end_rename; diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 495df7cd1..612bd6597 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -325,9 +325,6 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry) * Check whether the directory is not in use, then check * whether it is empty. */ - res = -EBUSY; - if (!d_unhashed(dentry)) - goto rmdir_done; res = fat_dir_empty(inode); if (res) goto rmdir_done; @@ -463,9 +460,6 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name, goto degenerate_case; if (is_dir) { if (new_inode) { - error = -EBUSY; - if (!d_unhashed(new_dentry)) - goto out; error = fat_dir_empty(new_inode); if (error) goto out; diff --git a/fs/namei.c b/fs/namei.c index 30dd1f7cf..7a94b38dd 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -286,11 +286,12 @@ static inline int follow_down(struct dentry ** dentry, struct vfsmount **mnt) * * We expect 'base' to be positive and a directory. */ -int walk_name(const char * name, unsigned lookup_flags, struct nameidata *nd) +int walk_name(const char * name, struct nameidata *nd) { struct dentry *dentry; struct inode *inode; int err; + unsigned int lookup_flags = nd->flags; while (*name=='/') name++; @@ -301,9 +302,6 @@ int walk_name(const char * name, unsigned lookup_flags, struct nameidata *nd) if (current->link_count) lookup_flags = LOOKUP_FOLLOW; - lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY | - LOOKUP_SLASHOK | LOOKUP_POSITIVE | LOOKUP_PARENT; - /* At this point we know we have a real path component. */ for(;;) { unsigned long hash; @@ -379,10 +377,10 @@ int walk_name(const char * name, unsigned lookup_flags, struct nameidata *nd) err = -ENOENT; inode = dentry->d_inode; if (!inode) - break; + goto out_dput; err = -ENOTDIR; if (!inode->i_op) - break; + goto out_dput; if (inode->i_op->follow_link) { err = do_follow_link(dentry, nd); @@ -464,16 +462,23 @@ last_component: goto return_base; no_inode: err = -ENOENT; - if (lookup_flags & LOOKUP_POSITIVE) + if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY)) break; - if (lookup_flags & LOOKUP_DIRECTORY) - if (!(lookup_flags & LOOKUP_SLASHOK)) - break; goto return_base; lookup_parent: nd->last = this; + nd->last_type = LAST_NORM; + if (this.name[0] != '.') + goto return_base; + if (this.len == 1) + nd->last_type = LAST_DOT; + else if (this.len == 2 && this.name[1] == '.') + nd->last_type = LAST_DOTDOT; return_base: return 0; +out_dput: + dput(dentry); + break; } dput(nd->dentry); mntput(nd->mnt); @@ -482,27 +487,20 @@ return_err: } /* returns 1 if everything is done */ -static int __emul_lookup_dentry(const char *name, int lookup_flags, - struct nameidata *nd) +static int __emul_lookup_dentry(const char *name, struct nameidata *nd) { - char *emul = __emul_prefix(); - - if (!emul) - return 0; - - nd->mnt = mntget(current->fs->rootmnt); - nd->dentry = dget(current->fs->root); - if (walk_name(emul,LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_POSITIVE,nd)) - return 0; - if (walk_name(name, lookup_flags, nd)) + nd->mnt = mntget(current->fs->altrootmnt); + nd->dentry = dget(current->fs->altroot); + if (walk_name(name, nd)) return 0; if (!nd->dentry->d_inode) { struct nameidata nd_root; - nd_root.last.len = 0; + nd_root.last_type = LAST_ROOT; + nd_root.flags = nd->flags; nd_root.mnt = mntget(current->fs->rootmnt); nd_root.dentry = dget(current->fs->root); - if (walk_name(name, lookup_flags, &nd_root)) + if (walk_name(name, &nd_root)) return 1; if (nd_root.dentry->d_inode) { dput(nd->dentry); @@ -518,11 +516,36 @@ static int __emul_lookup_dentry(const char *name, int lookup_flags, return 1; } +void set_fs_altroot(void) +{ + char *emul = __emul_prefix(); + struct nameidata nd; + struct vfsmount *mnt = NULL, *oldmnt; + struct dentry *dentry = NULL, *olddentry; + if (emul) { + nd.mnt = mntget(current->fs->rootmnt); + nd.dentry = dget(current->fs->root); + nd.flags = LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_POSITIVE; + if (walk_name(emul,&nd) == 0) { + mnt = nd.mnt; + dentry = nd.dentry; + } + } + oldmnt = current->fs->altrootmnt; + olddentry = current->fs->altroot; + current->fs->altrootmnt = mnt; + current->fs->altroot = dentry; + if (olddentry) { + dput(olddentry); + mntput(oldmnt); + } +} + static inline int -walk_init_root(const char *name, unsigned flags, struct nameidata *nd) +walk_init_root(const char *name, struct nameidata *nd) { - if (current->personality != PER_LINUX) - if (__emul_lookup_dentry(name,flags,nd)) + if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) + if (__emul_lookup_dentry(name,nd)) return 0; nd->mnt = mntget(current->fs->rootmnt); nd->dentry = dget(current->fs->root); @@ -531,9 +554,10 @@ walk_init_root(const char *name, unsigned flags, struct nameidata *nd) int walk_init(const char *name,unsigned int flags,struct nameidata *nd) { - nd->last.len = 0; + nd->last_type = LAST_ROOT; /* if there are only slashes... */ + nd->flags = flags; if (*name=='/') - return walk_init_root(name,flags,nd); + return walk_init_root(name,nd); nd->mnt = mntget(current->fs->pwdmnt); nd->dentry = dget(current->fs->pwd); return 1; @@ -545,7 +569,7 @@ struct dentry * lookup_dentry(const char * name, unsigned int lookup_flags) int err = 0; if (walk_init(name, lookup_flags, &nd)) - err = walk_name(name, lookup_flags, &nd); + err = walk_name(name, &nd); if (!err) { mntput(nd.mnt); return nd.dentry; @@ -589,15 +613,10 @@ static inline struct dentry * lookup_hash(struct qstr *name, struct dentry * bas dentry = inode->i_op->lookup(inode, new); if (!dentry) dentry = new; - else { + else dput(new); - if (IS_ERR(dentry)) - goto out; - } } - out: - dput(base); return dentry; } @@ -689,6 +708,8 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) int error; if (!victim->d_inode || victim->d_parent->d_inode != dir) return -ENOENT; + if (IS_DEADDIR(dir)) + return -ENOENT; error = permission(dir,MAY_WRITE | MAY_EXEC); if (error) return error; @@ -720,6 +741,8 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) static inline int may_create(struct inode *dir, struct dentry *child) { if (child->d_inode) return -EEXIST; + if (IS_DEADDIR(dir)) + return -ENOENT; return permission(dir,MAY_WRITE | MAY_EXEC); } @@ -790,7 +813,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) acc_mode = ACC_MODE(flag); if (!(flag & O_CREAT)) { if (walk_init(pathname, lookup_flags(flag), nd)) - error = walk_name(pathname, lookup_flags(flag), nd); + error = walk_name(pathname, nd); if (error) return error; @@ -799,7 +822,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) struct dentry *dir; if (walk_init(pathname, LOOKUP_PARENT, nd)) - error = walk_name(pathname, LOOKUP_PARENT, nd); + error = walk_name(pathname, nd); if (error) return error; /* @@ -810,9 +833,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) * luserdom and let him sod off - -EISDIR it is. */ error = -EISDIR; - if (!nd->last.len || (nd->last.name[0] == '.' && - (nd->last.len == 1 || - (nd->last.name[1] == '.' && nd->last.len == 2)))) + if (nd->last_type != LAST_NORM) goto exit; /* same for foo/ */ if (nd->last.name[nd->last.len]) @@ -821,7 +842,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) dir = dget(nd->dentry); down(&dir->d_inode->i_sem); - dentry = lookup_hash(&nd->last, dget(nd->dentry)); + dentry = lookup_hash(&nd->last, nd->dentry); error = PTR_ERR(dentry); if (IS_ERR(dentry)) { up(&dir->d_inode->i_sem); @@ -834,7 +855,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) dput(dir); error = -EEXIST; if (flag & O_EXCL) - goto exit; + goto exit_dput; if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link) { /* @@ -936,6 +957,8 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) return 0; +exit_dput: + dput(dentry); exit: dput(nd->dentry); mntput(nd->mnt); @@ -948,16 +971,15 @@ static struct dentry *lookup_create(const char *name, int is_dir) struct dentry *dentry; int err = 0; if (walk_init(name, LOOKUP_PARENT, &nd)) - err = walk_name(name, LOOKUP_PARENT, &nd); + err = walk_name(name, &nd); dentry = ERR_PTR(err); if (err) goto out; down(&nd.dentry->d_inode->i_sem); dentry = ERR_PTR(-EEXIST); - if (!nd.last.len || (nd.last.name[0] == '.' && - (nd.last.len == 1 || (nd.last.name[1] == '.' && nd.last.len == 2)))) + if (nd.last_type != LAST_NORM) goto fail; - dentry = lookup_hash(&nd.last, dget(nd.dentry)); + dentry = lookup_hash(&nd.last, nd.dentry); if (IS_ERR(dentry)) goto fail; if (!is_dir && nd.last.name[nd.last.len] && !dentry->d_inode) @@ -1155,47 +1177,53 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) double_down(&dir->i_zombie, &dentry->d_inode->i_zombie); d_unhash(dentry); error = dir->i_op->rmdir(dir, dentry); + if (!error) + dentry->d_inode->i_flags |= S_DEAD; double_up(&dir->i_zombie, &dentry->d_inode->i_zombie); dput(dentry); return error; } -static inline int do_rmdir(const char * name) +asmlinkage long sys_rmdir(const char * pathname) { - int error; - struct dentry *dir; + int error = 0; + char * name; struct dentry *dentry; + struct nameidata nd; - dentry = lookup_dentry(name, LOOKUP_POSITIVE); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) + name = getname(pathname); + if(IS_ERR(name)) + return PTR_ERR(name); + lock_kernel(); + + if (walk_init(name, LOOKUP_PARENT, &nd)) + error = walk_name(name, &nd); + if (error) goto exit; - dir = lock_parent(dentry); - error = -ENOENT; - if (check_parent(dir, dentry)) - error = vfs_rmdir(dir->d_inode, dentry); - unlock_dir(dir); - dput(dentry); + switch(nd.last_type) { + case LAST_DOTDOT: + error = -ENOTEMPTY; + goto exit1; + case LAST_ROOT: case LAST_DOT: + error = -EBUSY; + goto exit1; + } + down(&nd.dentry->d_inode->i_sem); + dentry = lookup_hash(&nd.last, nd.dentry); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + error = vfs_rmdir(nd.dentry->d_inode, dentry); + dput(dentry); + } + up(&nd.dentry->d_inode->i_sem); +exit1: + dput(nd.dentry); + mntput(nd.mnt); exit: - return error; -} - -asmlinkage long sys_rmdir(const char * pathname) -{ - int error; - char * tmp; - - tmp = getname(pathname); - if(IS_ERR(tmp)) - return PTR_ERR(tmp); - lock_kernel(); - error = do_rmdir(tmp); unlock_kernel(); - - putname(tmp); - + putname(name); return error; } @@ -1216,42 +1244,50 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) return error; } -static int do_unlink(const char * name) +asmlinkage long sys_unlink(const char * pathname) { - int error; - struct dentry *dir; + int error = 0; + char * name; struct dentry *dentry; + struct nameidata nd; - dentry = lookup_dentry(name, LOOKUP_POSITIVE); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) - goto exit; - - dir = lock_parent(dentry); - error = -ENOENT; - if (check_parent(dir, dentry)) - error = vfs_unlink(dir->d_inode, dentry); + name = getname(pathname); + if(IS_ERR(name)) + return PTR_ERR(name); + lock_kernel(); - unlock_dir(dir); - dput(dentry); + if (walk_init(name, LOOKUP_PARENT, &nd)) + error = walk_name(name, &nd); + if (error) + goto exit; + error = -EISDIR; + if (nd.last_type != LAST_NORM) + goto exit1; + down(&nd.dentry->d_inode->i_sem); + dentry = lookup_hash(&nd.last, nd.dentry); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + /* Why not before? Because we want correct error value */ + if (nd.last.name[nd.last.len]) + goto slashes; + error = vfs_unlink(nd.dentry->d_inode, dentry); + exit2: + dput(dentry); + } + up(&nd.dentry->d_inode->i_sem); +exit1: + dput(nd.dentry); + mntput(nd.mnt); exit: - return error; -} - -asmlinkage long sys_unlink(const char * pathname) -{ - int error; - char * tmp; - - tmp = getname(pathname); - if(IS_ERR(tmp)) - return PTR_ERR(tmp); - lock_kernel(); - error = do_unlink(tmp); unlock_kernel(); - putname(tmp); + putname(name); return error; + +slashes: + error = !dentry->d_inode ? -ENOENT : + S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR; + goto exit2; } int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) @@ -1468,6 +1504,8 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, &new_dir->i_zombie); error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); if (target) { + if (!error) + target->i_flags |= S_DEAD; triple_up(&old_dir->i_zombie, &new_dir->i_zombie, &target->i_zombie); @@ -1534,41 +1572,72 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, static inline int do_rename(const char * oldname, const char * newname) { - int error; + int error = 0; struct dentry * old_dir, * new_dir; struct dentry * old_dentry, *new_dentry; + struct nameidata oldnd, newnd; - old_dentry = lookup_dentry(oldname, LOOKUP_POSITIVE); + if (walk_init(oldname, LOOKUP_PARENT, &oldnd)) + error = walk_name(oldname, &oldnd); - error = PTR_ERR(old_dentry); - if (IS_ERR(old_dentry)) + if (error) goto exit; - { - unsigned int flags = 0; - if (S_ISDIR(old_dentry->d_inode->i_mode)) - flags = LOOKUP_SLASHOK; - new_dentry = lookup_dentry(newname, flags); - } + if (walk_init(newname, LOOKUP_PARENT, &newnd)) + error = walk_name(newname, &newnd); + if (error) + goto exit1; - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) - goto exit_old; + error = -EXDEV; + if (oldnd.mnt != newnd.mnt) + goto exit2; - new_dir = get_parent(new_dentry); - old_dir = get_parent(old_dentry); + old_dir = oldnd.dentry; + error = -EBUSY; + if (oldnd.last_type != LAST_NORM) + goto exit2; + + new_dir = newnd.dentry; + if (newnd.last_type != LAST_NORM) + goto exit2; double_lock(new_dir, old_dir); + old_dentry = lookup_hash(&oldnd.last, old_dir); + error = PTR_ERR(old_dentry); + if (IS_ERR(old_dentry)) + goto exit3; + /* source must exist */ error = -ENOENT; - if (check_parent(old_dir, old_dentry) && check_parent(new_dir, new_dentry)) - error = vfs_rename(old_dir->d_inode, old_dentry, + if (!old_dentry->d_inode) + goto exit4; + /* unless the source is a directory trailing slashes give -ENOTDIR */ + if (!S_ISDIR(old_dentry->d_inode->i_mode)) { + error = -ENOTDIR; + if (oldnd.last.name[oldnd.last.len]) + goto exit4; + if (newnd.last.name[newnd.last.len]) + goto exit4; + } + new_dentry = lookup_hash(&newnd.last, new_dir); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) + goto exit4; + + error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); - double_unlock(new_dir, old_dir); dput(new_dentry); -exit_old: +exit4: dput(old_dentry); +exit3: + double_up(&new_dir->d_inode->i_sem, &old_dir->d_inode->i_sem); +exit2: + dput(newnd.dentry); + mntput(newnd.mnt); +exit1: + dput(oldnd.dentry); + mntput(oldnd.mnt); exit: return error; } @@ -1620,11 +1689,11 @@ __vfs_follow_link(struct nameidata *nd, const char *link) if (*link == '/') { dput(nd->dentry); mntput(nd->mnt); - if (!walk_init_root(link, LOOKUP_FOLLOW, nd)) + if (!walk_init_root(link, nd)) /* weird __emul_prefix() stuff did it */ return 0; } - return walk_name(link, LOOKUP_FOLLOW, nd); + return walk_name(link, nd); fail: dput(nd->dentry); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 7d80e6468..2d2ee4a02 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -891,7 +891,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name); dfprintk(VFS, "trying to rename %s to %s\n", dentry->d_name.name, silly); - sdentry = lookup_one(silly, dget(dentry->d_parent)); + sdentry = lookup_one(silly, dentry->d_parent); /* * N.B. Better to return EBUSY here ... it could be * dangerous to delete the file while it's in use. diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d5c3d0944..44e71719c 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -74,6 +74,11 @@ nfs_file_flush(struct file *file) dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino); + /* Make sure all async reads have been sent off. We don't bother + * waiting on them though... */ + if (file->f_mode & FMODE_READ) + nfs_pagein_inode(inode, 0, 0); + status = nfs_wb_file(inode, file); if (!status) { status = file->f_error; @@ -166,8 +171,36 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse return status; } +/* + * The following is used by wait_on_page(), generic_file_readahead() + * to initiate the completion of any page readahead operations. + */ +static int nfs_sync_page(struct page *page) +{ + struct inode *inode = (struct inode *)page->mapping->host; + unsigned long index = page_index(page); + unsigned int rpages, wpages; + int result; + + if (!inode) + return 0; + + rpages = NFS_SERVER(inode)->rpages; + result = nfs_pagein_inode(inode, index, rpages); + if (result < 0) + goto out_bad; + wpages = NFS_SERVER(inode)->wpages; + result = nfs_sync_file(inode, NULL, index, wpages, FLUSH_STABLE); + if (result < 0) + goto out_bad; + return 0; + out_bad: + return result; +} + struct address_space_operations nfs_file_aops = { readpage: nfs_readpage, + sync_page: nfs_sync_page, writepage: nfs_writepage, prepare_write: nfs_prepare_write, commit_write: nfs_commit_write diff --git a/fs/nfs/flushd.c b/fs/nfs/flushd.c index 800a42171..460d4eba9 100644 --- a/fs/nfs/flushd.c +++ b/fs/nfs/flushd.c @@ -250,16 +250,18 @@ nfs_flushd(struct rpc_task *task) NFS_FLAGS(inode) &= ~NFS_INO_FLUSH; if (flush) { + nfs_pagein_inode(inode, 0, 0); nfs_sync_file(inode, NULL, 0, 0, FLUSH_AGING); } else if (time_after(jiffies, NFS_NEXTSCAN(inode))) { NFS_NEXTSCAN(inode) = jiffies + NFS_WRITEBACK_LOCKDELAY; + nfs_pagein_timeout(inode); nfs_flush_timeout(inode, FLUSH_AGING); #ifdef CONFIG_NFS_V3 nfs_commit_timeout(inode, FLUSH_AGING); #endif } - if (nfs_have_writebacks(inode)) { + if (nfs_have_writebacks(inode) || nfs_have_read(inode)) { inode_append_flushd(inode); if (time_after(delay, NFS_NEXTSCAN(inode))) delay = NFS_NEXTSCAN(inode); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 56271c14b..2d71aa7b5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -101,9 +101,11 @@ nfs_read_inode(struct inode * inode) inode->i_rdev = 0; NFS_FILEID(inode) = 0; NFS_FSID(inode) = 0; + INIT_LIST_HEAD(&inode->u.nfs_i.read); INIT_LIST_HEAD(&inode->u.nfs_i.dirty); INIT_LIST_HEAD(&inode->u.nfs_i.commit); INIT_LIST_HEAD(&inode->u.nfs_i.writeback); + inode->u.nfs_i.nread = 0; inode->u.nfs_i.ndirty = 0; inode->u.nfs_i.ncommit = 0; inode->u.nfs_i.npages = 0; @@ -131,7 +133,7 @@ nfs_delete_inode(struct inode * inode) /* * The following can never actually happen... */ - if (nfs_have_writebacks(inode)) { + if (nfs_have_writebacks(inode) || nfs_have_read(inode)) { printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino); } @@ -260,6 +262,7 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) struct nfs_fsinfo fsinfo; int tcp, version, maxlen; + memset(&sb->u.nfs_sb, 0, sizeof(sb->u.nfs_sb)); if (!data) goto out_miss_args; @@ -428,12 +431,20 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits); if (server->rsize > fsinfo.rtmax) server->rsize = fsinfo.rtmax; - if (server->rsize > PAGE_CACHE_SIZE) - server->rsize = PAGE_CACHE_SIZE; if (server->wsize > fsinfo.wtmax) server->wsize = fsinfo.wtmax; - if (server->wsize > NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT) - server->wsize = NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT; + + server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + if (server->rpages > NFS_READ_MAXIOV) { + server->rpages = NFS_READ_MAXIOV; + server->rsize = server->rpages << PAGE_CACHE_SHIFT; + } + + server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + if (server->wpages > NFS_WRITE_MAXIOV) { + server->wpages = NFS_WRITE_MAXIOV; + server->wsize = server->wpages << PAGE_CACHE_SHIFT; + } maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN; @@ -1145,6 +1156,8 @@ extern int nfs_init_fhcache(void); extern void nfs_destroy_fhcache(void); extern int nfs_init_nfspagecache(void); extern void nfs_destroy_nfspagecache(void); +extern int nfs_init_readpagecache(void); +extern int nfs_destroy_readpagecache(void); /* * Initialize NFS @@ -1162,6 +1175,10 @@ init_nfs_fs(void) if (err) return err; + err = nfs_init_readpagecache(); + if (err) + return err; + #ifdef CONFIG_PROC_FS rpc_proc_register(&nfs_rpcstat); #endif @@ -1186,6 +1203,7 @@ init_module(void) void cleanup_module(void) { + nfs_destroy_readpagecache(); nfs_destroy_nfspagecache(); nfs_destroy_fhcache(); #ifdef CONFIG_PROC_FS diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 0adfacd3e..980f90b98 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -120,10 +120,12 @@ xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path) static int xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) { - memset((u8 *)res, 0, sizeof(*res)); + struct nfs_fh *fh = res->fh; + + memset((void *)fh, 0, sizeof(*fh)); if ((res->status = ntohl(*p++)) == 0) { - res->fh->size = NFS2_FHSIZE; - memcpy(res->fh->data, p, NFS2_FHSIZE); + fh->size = NFS2_FHSIZE; + memcpy(fh->data, p, NFS2_FHSIZE); } return 0; } @@ -131,12 +133,14 @@ xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) static int xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) { - memset((u8 *)res, 0, sizeof(*res)); + struct nfs_fh *fh = res->fh; + + memset((void *)fh, 0, sizeof(*fh)); if ((res->status = ntohl(*p++)) == 0) { int size = ntohl(*p++); if (size <= NFS3_FHSIZE) { - res->fh->size = size; - memcpy(res->fh->data, p, res->fh->size); + fh->size = size; + memcpy(fh->data, p, size); } else res->status = -EBADHANDLE; } diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index b632cf175..7c3a7a0cc 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -450,32 +450,16 @@ static int __init root_nfs_get_handle(void) return status; } - -/* - * Now actually mount the given directory. - */ -static int __init root_nfs_do_mount(struct super_block *sb) -{ - /* Pass the server address to NFS */ - set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port); - - /* Now (finally ;-)) read the super block for mounting */ - if (nfs_read_super(sb, &nfs_data, 1) == NULL) - return -1; - return 0; -} - - /* - * Get the NFS port numbers and file handle, and then read the super- - * block for mounting. + * Get the NFS port numbers and file handle, and return the prepared 'data' + * argument for ->read_super() if everything went OK. Return NULL otherwise. */ -int __init nfs_root_mount(struct super_block *sb) +void * __init nfs_root_data(void) { if (root_nfs_init() < 0 || root_nfs_ports() < 0 - || root_nfs_get_handle() < 0 - || root_nfs_do_mount(sb) < 0) - return -1; - return 0; + || root_nfs_get_handle() < 0) + return NULL; + set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port); + return (void*)&nfs_data; } diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4cf51ec8d..aa01a2b64 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -25,6 +25,8 @@ #include <linux/pagemap.h> #include <linux/sunrpc/clnt.h> #include <linux/nfs_fs.h> +#include <linux/nfs_page.h> +#include <linux/nfs_flushd.h> #include <linux/smp_lock.h> #include <asm/segment.h> @@ -32,54 +34,65 @@ #define NFSDBG_FACILITY NFSDBG_PAGECACHE -struct nfs_rreq { - struct inode * ra_inode; /* inode from which to read */ - struct page * ra_page; /* page to be read */ - struct nfs_readargs ra_args; /* XDR argument struct */ - struct nfs_readres ra_res; /* ... and result struct */ - struct nfs_fattr ra_fattr; /* fattr storage */ +struct nfs_read_data { + struct rpc_task task; + struct dentry *dentry; + struct rpc_cred *cred; + struct nfs_readargs args; /* XDR argument struct */ + struct nfs_readres res; /* ... and result struct */ + struct nfs_fattr fattr; /* fattr storage */ + struct list_head pages; /* Coalesced read requests */ }; +/* + * Local function declarations + */ +static void nfs_readpage_result(struct rpc_task *task); + /* Hack for future NFS swap support */ #ifndef IS_SWAPFILE # define IS_SWAPFILE(inode) (0) #endif +static kmem_cache_t *nfs_rdata_cachep = NULL; -/* - * Set up the NFS read request struct - */ -static inline void -nfs_readreq_setup(struct nfs_rreq *req, struct nfs_fh *fh, - loff_t offset, void *buffer, unsigned int rsize) +static __inline__ struct nfs_read_data *nfs_readdata_alloc(void) { - req->ra_args.fh = fh; - req->ra_args.offset = offset; - req->ra_args.count = rsize; - req->ra_args.iov[0].iov_base = (void *)buffer; - req->ra_args.iov[0].iov_len = rsize; - req->ra_args.nriov = 1; - req->ra_fattr.valid = 0; - req->ra_res.fattr = &req->ra_fattr; - req->ra_res.count = rsize; - req->ra_res.eof = 0; + struct nfs_read_data *p; + p = kmem_cache_alloc(nfs_rdata_cachep, SLAB_NFS); + if (p) { + memset(p, 0, sizeof(*p)); + INIT_LIST_HEAD(&p->pages); + } + return p; } +static __inline__ void nfs_readdata_free(struct nfs_read_data *p) +{ + kmem_cache_free(nfs_rdata_cachep, p); +} + +static void nfs_readdata_release(struct rpc_task *task) +{ + struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; + nfs_readdata_free(data); +} /* * Read a page synchronously. */ static int -nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page) +nfs_readpage_sync(struct dentry *dentry, struct page *page) { - struct nfs_rreq rqst; - struct rpc_message msg; + struct inode *inode = dentry->d_inode; + struct nfs_fattr fattr; loff_t offset = page_offset(page); char *buffer; int rsize = NFS_SERVER(inode)->rsize; - int result, refresh = 0; + int result; int count = PAGE_CACHE_SIZE; int flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0; + int eof; dprintk("NFS: nfs_readpage_sync(%p)\n", page); @@ -87,8 +100,7 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page) * This works now because the socket layer never tries to DMA * into this buffer directly. */ - buffer = (char *) kmap(page); - + buffer = (char *) kmap(page); do { if (count < rsize) rsize = count; @@ -98,16 +110,11 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page) dentry->d_parent->d_name.name, dentry->d_name.name, (long long)offset, rsize, buffer); - /* Set up arguments and perform rpc call */ - nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize); lock_kernel(); - msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ; - msg.rpc_argp = &rqst.ra_args; - msg.rpc_resp = &rqst.ra_res; - msg.rpc_cred = NULL; - result = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); + result = NFS_PROTO(inode)->read(dentry, &fattr, flags, offset, + rsize, buffer, &eof); unlock_kernel(); - nfs_refresh_inode(inode, &rqst.ra_fattr); + nfs_refresh_inode(inode, &fattr); /* * Even if we had a partial success we can't mark the page @@ -118,7 +125,6 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page) result = -EINVAL; goto io_error; } - refresh = 1; count -= result; offset += result; buffer += result; @@ -128,6 +134,8 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page) memset(buffer, 0, count); SetPageUptodate(page); + if (PageError(page)) + ClearPageError(page); result = 0; io_error: @@ -136,92 +144,318 @@ io_error: return result; } +static inline struct nfs_page * +_nfs_find_read(struct inode *inode, struct page *page) +{ + struct list_head *head, *next; + + head = &inode->u.nfs_i.read; + next = head->next; + while (next != head) { + struct nfs_page *req = nfs_list_entry(next); + next = next->next; + if (page_index(req->wb_page) != page_index(page)) + continue; + req->wb_count++; + return req; + } + return NULL; +} + +static struct nfs_page * +nfs_find_read(struct inode *inode, struct page *page) +{ + struct nfs_page *req; + spin_lock(&nfs_wreq_lock); + req = _nfs_find_read(inode, page); + spin_unlock(&nfs_wreq_lock); + return req; +} + /* - * This is the callback from RPC telling us whether a reply was - * received or some error occurred (timeout or socket shutdown). + * Add a request to the inode's asynchronous read list. */ -static void -nfs_readpage_result(struct rpc_task *task) +static inline void +nfs_mark_request_read(struct nfs_page *req) { - struct nfs_rreq *req = (struct nfs_rreq *) task->tk_calldata; - struct page *page = req->ra_page; - char *address = req->ra_args.iov[0].iov_base; - int result = task->tk_status; - static int succ = 0, fail = 0; - - dprintk("NFS: %4d received callback for page %p, result %d\n", - task->tk_pid, address, result); - - nfs_refresh_inode(req->ra_inode, &req->ra_fattr); - if (result >= 0) { - result = req->ra_res.count; - if (result < PAGE_CACHE_SIZE) - memset(address + result, 0, PAGE_CACHE_SIZE - result); - SetPageUptodate(page); - succ++; - } else { - SetPageError(page); - fail++; - dprintk("NFS: %d successful reads, %d failures\n", succ, fail); + struct inode *inode = req->wb_dentry->d_inode; + + spin_lock(&nfs_wreq_lock); + if (list_empty(&req->wb_list)) { + nfs_list_add_request(req, &inode->u.nfs_i.read); + inode->u.nfs_i.nread++; } - kunmap(page); - UnlockPage(page); - page_cache_release(page); + spin_unlock(&nfs_wreq_lock); + /* + * NB: the call to inode_schedule_scan() must lie outside the + * spinlock since it can run flushd(). + */ + inode_schedule_scan(inode, req->wb_timeout); +} + +static int +nfs_readpage_async(struct dentry *dentry, struct page *page) +{ + struct inode *inode = dentry->d_inode; + struct nfs_page *req, *new = NULL; + int result; + + for (;;) { + result = 0; + if (Page_Uptodate(page)) + break; - kfree(req); + req = nfs_find_read(inode, page); + if (req) { + if (page != req->wb_page) { + nfs_release_request(req); + nfs_pagein_inode(inode, page_index(page), 0); + continue; + } + nfs_release_request(req); + break; + } + + if (new) { + nfs_lock_request(new); + new->wb_timeout = jiffies + NFS_READ_DELAY; + nfs_mark_request_read(new); + nfs_unlock_request(new); + new = NULL; + break; + } + + result = -ENOMEM; + new = nfs_create_request(dentry, page, 0, PAGE_CACHE_SIZE); + if (!new) + break; + } + + if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages || + page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) + nfs_pagein_inode(inode, 0, 0); + if (new) + nfs_release_request(new); + return result; +} + +/* + * Set up the NFS read request struct + */ +static void +nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data) +{ + struct nfs_page *req; + struct iovec *iov; + unsigned int count; + + iov = data->args.iov; + count = 0; + while (!list_empty(head)) { + struct nfs_page *req = nfs_list_entry(head->next); + nfs_list_remove_request(req); + nfs_list_add_request(req, &data->pages); + iov->iov_base = (void *)(kmap(req->wb_page) + req->wb_offset); + iov->iov_len = req->wb_bytes; + count += req->wb_bytes; + iov++; + data->args.nriov++; + } + req = nfs_list_entry(data->pages.next); + data->dentry = req->wb_dentry; + data->cred = req->wb_cred; + data->args.fh = NFS_FH(req->wb_dentry); + data->args.offset = page_offset(req->wb_page) + req->wb_offset; + data->args.count = count; + data->res.fattr = &data->fattr; + data->res.count = count; + data->res.eof = 0; } -static inline int -nfs_readpage_async(struct dentry *dentry, struct inode *inode, - struct page *page) +static void +nfs_async_read_error(struct list_head *head) { - struct rpc_message msg; - unsigned long address; - struct nfs_rreq *req; - int result = -1, flags; + struct nfs_page *req; + struct page *page; + + while (!list_empty(head)) { + req = nfs_list_entry(head->next); + page = req->wb_page; + nfs_list_remove_request(req); + SetPageError(page); + UnlockPage(page); + nfs_unlock_request(req); + nfs_release_request(req); + } +} - dprintk("NFS: nfs_readpage_async(%p)\n", page); - if (NFS_CONGESTED(inode)) - goto out_defer; +static int +nfs_pagein_one(struct list_head *head, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct rpc_task *task; + struct rpc_clnt *clnt = NFS_CLIENT(inode); + struct nfs_read_data *data; + struct rpc_message msg; + int flags; + sigset_t oldset; + + data = nfs_readdata_alloc(); + if (!data) + goto out_bad; + task = &data->task; /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); - req = (struct nfs_rreq *) rpc_allocate(flags, sizeof(*req)); - if (!req) - goto out_defer; - - address = kmap(page); - /* Initialize request */ - /* N.B. Will the dentry remain valid for life of request? */ - nfs_readreq_setup(req, NFS_FH(dentry), page_offset(page), - (void *) address, PAGE_CACHE_SIZE); - req->ra_inode = inode; - req->ra_page = page; /* count has been incremented by caller */ - /* Start the async call */ - dprintk("NFS: executing async READ request.\n"); + nfs_read_rpcsetup(head, data); + + /* Finalize the task. */ + rpc_init_task(task, clnt, nfs_readpage_result, flags); + task->tk_calldata = data; + /* Release requests */ + task->tk_release = nfs_readdata_release; +#ifdef CONFIG_NFS_V3 msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ; - msg.rpc_argp = &req->ra_args; - msg.rpc_resp = &req->ra_res; - msg.rpc_cred = NULL; - - result = rpc_call_async(NFS_CLIENT(inode), &msg, flags, - nfs_readpage_result, req); - if (result < 0) - goto out_free; - result = 0; -out: - return result; +#else + msg.rpc_proc = NFSPROC_READ; +#endif + msg.rpc_argp = &data->args; + msg.rpc_resp = &data->res; + msg.rpc_cred = data->cred; -out_defer: - dprintk("NFS: deferring async READ request.\n"); - goto out; -out_free: - dprintk("NFS: failed to enqueue async READ request.\n"); - kunmap(page); - kfree(req); - goto out; + /* Start the async call */ + dprintk("NFS: %4d initiated read call (req %s/%s count %d nriov %d.\n", + task->tk_pid, + dentry->d_parent->d_name.name, dentry->d_name.name, + data->args.count, data->args.nriov); + + rpc_clnt_sigmask(clnt, &oldset); + rpc_call_setup(task, &msg, 0); + rpc_execute(task); + rpc_clnt_sigunmask(clnt, &oldset); + return 0; +out_bad: + nfs_async_read_error(head); + return -ENOMEM; +} + +static int +nfs_pagein_list(struct inode *inode, struct list_head *head) +{ + LIST_HEAD(one_request); + struct nfs_page *req; + int error = 0; + unsigned int pages = 0, + rpages = NFS_SERVER(inode)->rpages; + + while (!list_empty(head)) { + pages += nfs_coalesce_requests(head, &one_request, rpages); + req = nfs_list_entry(one_request.next); + error = nfs_pagein_one(&one_request, req->wb_dentry); + if (error < 0) + break; + } + if (error >= 0) + return pages; + + nfs_async_read_error(head); + return error; +} + +static int +nfs_scan_read_timeout(struct inode *inode, struct list_head *dst) +{ + int pages; + spin_lock(&nfs_wreq_lock); + pages = nfs_scan_list_timeout(&inode->u.nfs_i.read, dst, inode); + inode->u.nfs_i.nread -= pages; + if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read)) + printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n"); + spin_unlock(&nfs_wreq_lock); + return pages; +} + +static int +nfs_scan_read(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) +{ + int res; + spin_lock(&nfs_wreq_lock); + res = nfs_scan_list(&inode->u.nfs_i.read, dst, NULL, idx_start, npages); + inode->u.nfs_i.nread -= res; + if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read)) + printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n"); + spin_unlock(&nfs_wreq_lock); + return res; +} + +int nfs_pagein_inode(struct inode *inode, unsigned long idx_start, + unsigned int npages) +{ + LIST_HEAD(head); + int res, + error = 0; + + res = nfs_scan_read(inode, &head, idx_start, npages); + if (res) + error = nfs_pagein_list(inode, &head); + if (error < 0) + return error; + return res; +} + +int nfs_pagein_timeout(struct inode *inode) +{ + LIST_HEAD(head); + int pages, + error = 0; + + pages = nfs_scan_read_timeout(inode, &head); + if (pages) + error = nfs_pagein_list(inode, &head); + if (error < 0) + return error; + return pages; +} + +/* + * This is the callback from RPC telling us whether a reply was + * received or some error occurred (timeout or socket shutdown). + */ +static void +nfs_readpage_result(struct rpc_task *task) +{ + struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; + struct dentry *dentry = data->dentry; + struct inode *inode = dentry->d_inode; + int count = data->res.count; + + dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", + task->tk_pid, task->tk_status); + + nfs_refresh_inode(inode, &data->fattr); + while (!list_empty(&data->pages)) { + struct nfs_page *req = nfs_list_entry(data->pages.next); + struct page *page = req->wb_page; + nfs_list_remove_request(req); + + if (task->tk_status >= 0 && count >= 0) { + SetPageUptodate(page); + count -= PAGE_CACHE_SIZE; + } else + SetPageError(page); + kunmap(page); + UnlockPage(page); + + dprintk("NFS: read (%s/%s %d@%Ld)\n", + req->wb_dentry->d_parent->d_name.name, + req->wb_dentry->d_name.name, + req->wb_bytes, + (long long)(page_offset(page) + req->wb_offset)); + nfs_unlock_request(req); + nfs_release_request(req); + } } /* @@ -242,11 +476,8 @@ nfs_readpage(struct dentry *dentry, struct page *page) struct inode *inode = dentry->d_inode; int error; - lock_kernel(); dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", page, PAGE_CACHE_SIZE, page->index); - get_page(page); - /* * Try to flush any pending writes to the file.. * @@ -259,22 +490,36 @@ nfs_readpage(struct dentry *dentry, struct page *page) goto out_error; error = -1; - if (!IS_SWAPFILE(inode) && !PageError(page) && - NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) - error = nfs_readpage_async(dentry, inode, page); + if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) + error = nfs_readpage_async(dentry, page); if (error >= 0) goto out; - error = nfs_readpage_sync(dentry, inode, page); + error = nfs_readpage_sync(dentry, page); if (error < 0 && IS_SWAPFILE(inode)) printk("Aiee.. nfs swap-in of page failed!\n"); - goto out_free; +out: + return error; out_error: UnlockPage(page); -out_free: - page_cache_release(page); -out: - unlock_kernel(); - return error; + goto out; +} + +int nfs_init_readpagecache(void) +{ + nfs_rdata_cachep = kmem_cache_create("nfs_read_data", + sizeof(struct nfs_read_data), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (nfs_rdata_cachep == NULL) + return -ENOMEM; + + return 0; +} + +void nfs_destroy_readpagecache(void) +{ + if (kmem_cache_destroy(nfs_rdata_cachep)) + printk(KERN_INFO "nfs_read_data: not all structures were freed\n"); } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 651251548..5ca6430aa 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -57,6 +57,7 @@ #include <linux/nfs_fs.h> #include <linux/nfs_mount.h> #include <linux/nfs_flushd.h> +#include <linux/nfs_page.h> #include <asm/uaccess.h> #include <linux/smp_lock.h> @@ -72,16 +73,11 @@ static unsigned int nfs_nr_requests = 0; /* * Local structures * - * Valid flags for a dirty buffer - */ -#define PG_BUSY 0x0001 - -/* * This is the struct where the WRITE/COMMIT arguments go. */ struct nfs_write_data { struct rpc_task task; - struct file *file; + struct dentry *dentry; struct rpc_cred *cred; struct nfs_writeargs args; /* argument struct */ struct nfs_writeres res; /* result struct */ @@ -90,27 +86,13 @@ struct nfs_write_data { struct list_head pages; /* Coalesced requests we wish to flush */ }; -struct nfs_page { - struct list_head wb_hash, /* Inode */ - wb_list, - *wb_list_head; - struct file *wb_file; - struct rpc_cred *wb_cred; - struct page *wb_page; /* page to write out */ - wait_queue_head_t wb_wait; /* wait queue */ - unsigned long wb_timeout; /* when to write/commit */ - unsigned int wb_offset, /* Offset of write */ - wb_bytes, /* Length of request */ - wb_count, /* reference count */ - wb_flags; - struct nfs_writeverf wb_verf; /* Commit cookie */ -}; - -#define NFS_WBACK_BUSY(req) ((req)->wb_flags & PG_BUSY) - /* * Local function declarations */ +static struct nfs_page * nfs_update_request(struct file*, struct dentry *, + struct page *page, + unsigned int, unsigned int); +static void nfs_strategy(struct inode *inode); static void nfs_writeback_done(struct rpc_task *); #ifdef CONFIG_NFS_V3 static void nfs_commit_done(struct rpc_task *); @@ -186,9 +168,10 @@ nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr) * Offset is the data offset within the page. */ static int -nfs_writepage_sync(struct dentry *dentry, struct inode *inode, - struct page *page, unsigned long offset, unsigned int count) +nfs_writepage_sync(struct dentry *dentry, struct page *page, + unsigned int offset, unsigned int count) { + struct inode *inode = dentry->d_inode; loff_t base; unsigned int wsize = NFS_SERVER(inode)->wsize; int result, refresh = 0, written = 0, flags; @@ -197,9 +180,9 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode, struct nfs_writeverf verf; lock_kernel(); - dprintk("NFS: nfs_writepage_sync(%s/%s %d@%lu/%ld)\n", + dprintk("NFS: nfs_writepage_sync(%s/%s %d@%Ld)\n", dentry->d_parent->d_name.name, dentry->d_name.name, - count, page->index, offset); + count, (long long)(page_offset(page) + offset)); buffer = (u8 *) kmap(page) + offset; base = page_offset(page) + offset; @@ -235,6 +218,9 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode, inode->i_size = base; } while (count); + if (PageError(page)) + ClearPageError(page); + io_error: kunmap(page); @@ -242,14 +228,28 @@ io_error: return written? written : result; } +static int +nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page, + unsigned int offset, unsigned int count) +{ + struct nfs_page *req; + int status; + + req = nfs_update_request(file, dentry, page, offset, count); + status = (IS_ERR(req)) ? PTR_ERR(req) : 0; + if (status < 0) + goto out; + nfs_release_request(req); + nfs_strategy(dentry->d_inode); + out: + return status; +} + /* - * Write a page to the server. This was supposed to be used for - * NFS swapping only. - * FIXME: Using this for mmap is pointless, breaks asynchronous - * writebacks, and is extremely slow. + * Write an mmapped page to the server. */ int -nfs_writepage(struct dentry * dentry, struct page *page) +nfs_writepage(struct file *file, struct dentry * dentry, struct page *page) { struct inode *inode = dentry->d_inode; unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; @@ -265,9 +265,17 @@ nfs_writepage(struct dentry * dentry, struct page *page) if (page->index >= end_index+1 || !offset) return -EIO; do_it: - err = nfs_writepage_sync(dentry, inode, page, 0, offset); - if ( err == offset) return 0; + if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { + err = nfs_writepage_async(file, dentry, page, 0, offset); + if (err >= 0) + goto out_ok; + } + err = nfs_writepage_sync(dentry, page, 0, offset); + if ( err == offset) + goto out_ok; return err; + out_ok: + return 0; } /* @@ -297,12 +305,6 @@ region_locked(struct inode *inode, struct nfs_page *req) return 0; } -static inline struct nfs_page * -nfs_inode_wb_entry(struct list_head *head) -{ - return list_entry(head, struct nfs_page, wb_hash); -} - /* * Insert a write request into an inode */ @@ -332,13 +334,13 @@ nfs_inode_remove_request(struct nfs_page *req) } if (!NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n"); - inode = req->wb_file->f_dentry->d_inode; + inode = req->wb_dentry->d_inode; list_del(&req->wb_hash); INIT_LIST_HEAD(&req->wb_hash); inode->u.nfs_i.npages--; if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n"); - if (!nfs_have_writebacks(inode)) + if (!nfs_have_writebacks(inode) && !nfs_have_read(inode)) inode_remove_flushd(inode); spin_unlock(&nfs_wreq_lock); nfs_release_request(req); @@ -365,7 +367,7 @@ _nfs_find_request(struct inode *inode, struct page *page) return NULL; } -struct nfs_page * +static struct nfs_page * nfs_find_request(struct inode *inode, struct page *page) { struct nfs_page *req; @@ -376,17 +378,10 @@ nfs_find_request(struct inode *inode, struct page *page) return req; } -static inline struct nfs_page * -nfs_list_entry(struct list_head *head) -{ - return list_entry(head, struct nfs_page, wb_list); -} - /* * Insert a write request into a sorted list */ -static inline void -nfs_list_add_request(struct nfs_page *req, struct list_head *head) +void nfs_list_add_request(struct nfs_page *req, struct list_head *head) { struct list_head *prev; @@ -394,10 +389,6 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) printk(KERN_ERR "NFS: Add to list failed!\n"); return; } - if (list_empty(&req->wb_hash)) { - printk(KERN_ERR "NFS: Unhashed request attempted added to a list!\n"); - return; - } if (!NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: unlocked request attempted added to list!\n"); prev = head->prev; @@ -414,8 +405,7 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) /* * Insert a write request into an inode */ -static inline void -nfs_list_remove_request(struct nfs_page *req) +void nfs_list_remove_request(struct nfs_page *req) { if (list_empty(&req->wb_list)) return; @@ -432,7 +422,7 @@ nfs_list_remove_request(struct nfs_page *req) static inline void nfs_mark_request_dirty(struct nfs_page *req) { - struct inode *inode = req->wb_file->f_dentry->d_inode; + struct inode *inode = req->wb_dentry->d_inode; spin_lock(&nfs_wreq_lock); if (list_empty(&req->wb_list)) { @@ -453,7 +443,7 @@ nfs_mark_request_dirty(struct nfs_page *req) static inline int nfs_dirty_request(struct nfs_page *req) { - struct inode *inode = req->wb_file->f_dentry->d_inode; + struct inode *inode = req->wb_dentry->d_inode; return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty; } @@ -464,7 +454,7 @@ nfs_dirty_request(struct nfs_page *req) static inline void nfs_mark_request_commit(struct nfs_page *req) { - struct inode *inode = req->wb_file->f_dentry->d_inode; + struct inode *inode = req->wb_dentry->d_inode; spin_lock(&nfs_wreq_lock); if (list_empty(&req->wb_list)) { @@ -481,40 +471,15 @@ nfs_mark_request_commit(struct nfs_page *req) #endif /* - * Lock the page of an asynchronous request - */ -static inline int -nfs_lock_request(struct nfs_page *req) -{ - if (NFS_WBACK_BUSY(req)) - return 0; - req->wb_count++; - req->wb_flags |= PG_BUSY; - return 1; -} - -static inline void -nfs_unlock_request(struct nfs_page *req) -{ - if (!NFS_WBACK_BUSY(req)) { - printk(KERN_ERR "NFS: Invalid unlock attempted\n"); - return; - } - req->wb_flags &= ~PG_BUSY; - wake_up(&req->wb_wait); - nfs_release_request(req); -} - -/* * Create a write request. * Page must be locked by the caller. This makes sure we never create * two different requests for the same page, and avoids possible deadlock * when we reach the hard limit on the number of dirty pages. */ -static struct nfs_page * -nfs_create_request(struct inode *inode, struct file *file, struct page *page, - unsigned int offset, unsigned int count) +struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page, + unsigned int offset, unsigned int count) { + struct inode *inode = dentry->d_inode; struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct nfs_page *req = NULL; long timeout; @@ -522,11 +487,7 @@ nfs_create_request(struct inode *inode, struct file *file, struct page *page, /* Deal with hard/soft limits. */ do { - /* If we're over the soft limit, flush out old requests */ - if (nfs_nr_requests >= MAX_REQUEST_SOFT) - nfs_wb_file(inode, file); - - /* If we're still over the soft limit, wake up some requests */ + /* If we're over the global soft limit, wake up all requests */ if (nfs_nr_requests >= MAX_REQUEST_SOFT) { dprintk("NFS: hit soft limit (%d requests)\n", nfs_nr_requests); @@ -535,9 +496,9 @@ nfs_create_request(struct inode *inode, struct file *file, struct page *page, nfs_wake_flushd(); } - /* If we haven't reached the hard limit yet, + /* If we haven't reached the local hard limit yet, * try to allocate the request struct */ - if (nfs_nr_requests < MAX_REQUEST_HARD) { + if (cache->nr_requests < MAX_REQUEST_HARD) { req = nfs_page_alloc(); if (req != NULL) break; @@ -545,7 +506,7 @@ nfs_create_request(struct inode *inode, struct file *file, struct page *page, /* We're over the hard limit. Wait for better times */ dprintk("NFS: create_request sleeping (total %d pid %d)\n", - nfs_nr_requests, current->pid); + cache->nr_requests, current->pid); timeout = 1 * HZ; if (NFS_SERVER(inode)->flags & NFS_MOUNT_INTR) { @@ -557,7 +518,7 @@ nfs_create_request(struct inode *inode, struct file *file, struct page *page, sleep_on_timeout(&cache->request_wait, timeout); dprintk("NFS: create_request waking up (tot %d pid %d)\n", - nfs_nr_requests, current->pid); + cache->nr_requests, current->pid); } while (!req); if (!req) return NULL; @@ -566,17 +527,11 @@ nfs_create_request(struct inode *inode, struct file *file, struct page *page, * long write-back delay. This will be adjusted in * update_nfs_request below if the region is not locked. */ req->wb_page = page; - atomic_inc(&page->count); + get_page(page); req->wb_offset = offset; req->wb_bytes = count; - /* If the region is locked, adjust the timeout */ - if (region_locked(inode, req)) - req->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY; - else - req->wb_timeout = jiffies + NFS_WRITEBACK_DELAY; - req->wb_file = file; + req->wb_dentry = dget(dentry); req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); - get_file(file); req->wb_count = 1; /* register request's existence */ @@ -595,7 +550,7 @@ nfs_create_request(struct inode *inode, struct file *file, struct page *page, void nfs_release_request(struct nfs_page *req) { - struct inode *inode = req->wb_file->f_dentry->d_inode; + struct inode *inode = req->wb_dentry->d_inode; struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct page *page = req->wb_page; @@ -618,7 +573,11 @@ nfs_release_request(struct nfs_page *req) printk(KERN_ERR "NFS: Request released while still locked!\n"); rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred); - fput(req->wb_file); + lock_kernel(); + if (req->wb_file) + fput(req->wb_file); + dput(req->wb_dentry); + unlock_kernel(); page_cache_release(page); nfs_page_free(req); /* wake up anyone waiting to allocate a request */ @@ -635,7 +594,7 @@ nfs_release_request(struct nfs_page *req) static int nfs_wait_on_request(struct nfs_page *req) { - struct inode *inode = req->wb_file->f_dentry->d_inode; + struct inode *inode = req->wb_dentry->d_inode; struct rpc_clnt *clnt = NFS_CLIENT(inode); int retval; @@ -701,8 +660,7 @@ nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_s * Scan cluster for dirty pages and send as many of them to the * server as possible. */ -static int -nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode) +int nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode) { struct list_head *p; struct nfs_page *req; @@ -754,8 +712,7 @@ nfs_scan_commit_timeout(struct inode *inode, struct list_head *dst) } #endif -static int -nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) +int nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) { struct list_head *p; struct nfs_page *req; @@ -819,8 +776,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, u #endif -static int -coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages) +int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages) { struct nfs_page *req = NULL; unsigned int pages = 0; @@ -832,7 +788,10 @@ coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int max if (prev) { if (req->wb_file != prev->wb_file) break; - + if (req->wb_dentry != prev->wb_dentry) + break; + if (req->wb_cred != prev->wb_cred) + break; if (page_index(req->wb_page) != page_index(prev->wb_page)+1) break; @@ -858,10 +817,10 @@ coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int max * Note: Should always be called with the Page Lock held! */ static struct nfs_page * -nfs_update_request(struct file* file, struct page *page, - unsigned long offset, unsigned int bytes) +nfs_update_request(struct file* file, struct dentry *dentry, struct page *page, + unsigned int offset, unsigned int bytes) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = dentry->d_inode; struct nfs_page *req, *new = NULL; unsigned long rqend, end; @@ -896,12 +855,26 @@ nfs_update_request(struct file* file, struct page *page, } spin_unlock(&nfs_wreq_lock); + /* Create the request. It's safe to sleep in this call because * we only get here if the page is locked. + * + * If we're over the soft limit, flush out old requests */ - new = nfs_create_request(inode, file, page, offset, bytes); + if (file && nfs_nr_requests >= MAX_REQUEST_SOFT) + nfs_wb_file(inode, file); + new = nfs_create_request(dentry, page, offset, bytes); if (!new) return ERR_PTR(-ENOMEM); + if (file) { + new->wb_file = file; + get_file(file); + } + /* If the region is locked, adjust the timeout */ + if (region_locked(inode, new)) + new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY; + else + new->wb_timeout = jiffies + NFS_WRITEBACK_DELAY; } /* We have a request for our page. @@ -956,31 +929,33 @@ nfs_update_request(struct file* file, struct page *page, */ #define NFS_STRATEGY_PAGES 8 static void -nfs_strategy(struct file *file) +nfs_strategy(struct inode *inode) { - struct inode *inode = file->f_dentry->d_inode; unsigned int dirty, wpages; dirty = inode->u.nfs_i.ndirty; - wpages = NFS_SERVER(inode)->wsize >> PAGE_CACHE_SHIFT; + wpages = NFS_SERVER(inode)->wpages; #ifdef CONFIG_NFS_V3 if (NFS_PROTO(inode)->version == 2) { if (dirty >= NFS_STRATEGY_PAGES * wpages) - nfs_flush_file(inode, file, 0, 0, 0); + nfs_flush_file(inode, NULL, 0, 0, 0); } else { if (dirty >= wpages) - nfs_flush_file(inode, file, 0, 0, 0); + nfs_flush_file(inode, NULL, 0, 0, 0); + if (inode->u.nfs_i.ncommit > NFS_STRATEGY_PAGES * wpages && + nfs_nr_requests > MAX_REQUEST_SOFT) + nfs_commit_file(inode, NULL, 0, 0, 0); } #else if (dirty >= NFS_STRATEGY_PAGES * wpages) - nfs_flush_file(inode, file, 0, 0, 0); + nfs_flush_file(inode, NULL, 0, 0, 0); #endif /* - * If we're running out of requests, flush out everything + * If we're running out of free requests, flush out everything * in order to reduce memory useage... */ - if (nfs_nr_requests > MAX_REQUEST_SOFT) - nfs_wb_file(inode, file); + if (inode->u.nfs_i.npages > MAX_REQUEST_SOFT) + nfs_wb_all(inode); } int @@ -1013,7 +988,7 @@ nfs_flush_incompatible(struct file *file, struct page *page) * things with a page scheduled for an RPC call (e.g. invalidate it). */ int -nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsigned int count) +nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count) { struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; @@ -1030,7 +1005,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig * page synchronously. */ if (NFS_SERVER(inode)->wsize < PAGE_SIZE) - return nfs_writepage_sync(dentry, inode, page, offset, count); + return nfs_writepage_sync(dentry, page, offset, count); /* * Try to find an NFS request corresponding to this page @@ -1039,7 +1014,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig * it out now. */ do { - req = nfs_update_request(file, page, offset, count); + req = nfs_update_request(file, dentry, page, offset, count); status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (status != -EBUSY) break; @@ -1066,7 +1041,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig * of requests. */ if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE) - nfs_strategy(file); + nfs_strategy(inode); } nfs_release_request(req); done: @@ -1103,9 +1078,9 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data) data->args.nriov++; } req = nfs_list_entry(data->pages.next); - data->file = req->wb_file; + data->dentry = req->wb_dentry; data->cred = req->wb_cred; - data->args.fh = NFS_FH(req->wb_file->f_dentry); + data->args.fh = NFS_FH(req->wb_dentry); data->args.offset = page_offset(req->wb_page) + req->wb_offset; data->args.count = count; data->res.fattr = &data->fattr; @@ -1123,9 +1098,8 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data) * that has been written but not committed. */ static int -nfs_flush_one(struct list_head *head, struct file *file, int how) +nfs_flush_one(struct list_head *head, struct dentry *dentry, int how) { - struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; struct rpc_clnt *clnt = NFS_CLIENT(inode); struct nfs_write_data *data; @@ -1198,12 +1172,12 @@ nfs_flush_list(struct inode *inode, struct list_head *head, int how) struct nfs_page *req; int error = 0; unsigned int pages = 0, - wpages = NFS_SERVER(inode)->wsize >> PAGE_CACHE_SHIFT; + wpages = NFS_SERVER(inode)->wpages; while (!list_empty(head)) { - pages += coalesce_requests(head, &one_request, wpages); + pages += nfs_coalesce_requests(head, &one_request, wpages); req = nfs_list_entry(one_request.next); - error = nfs_flush_one(&one_request, req->wb_file, how); + error = nfs_flush_one(&one_request, req->wb_dentry, how); if (error < 0) break; } @@ -1229,9 +1203,10 @@ nfs_writeback_done(struct rpc_task *task) struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct nfs_writeargs *argp = &data->args; struct nfs_writeres *resp = &data->res; - struct dentry *dentry = data->file->f_dentry; + struct dentry *dentry = data->dentry; struct inode *inode = dentry->d_inode; struct nfs_page *req; + struct page *page; dprintk("NFS: %4d nfs_writeback_done (status %d)\n", task->tk_pid, task->tk_status); @@ -1276,17 +1251,21 @@ nfs_writeback_done(struct rpc_task *task) while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); + page = req->wb_page; - kunmap(req->wb_page); + kunmap(page); dprintk("NFS: write (%s/%s %d@%Ld)", - req->wb_file->f_dentry->d_parent->d_name.name, - req->wb_file->f_dentry->d_name.name, + req->wb_dentry->d_parent->d_name.name, + req->wb_dentry->d_name.name, req->wb_bytes, - (long long)(page_offset(req->wb_page) + req->wb_offset)); + (long long)(page_offset(page) + req->wb_offset)); if (task->tk_status < 0) { - req->wb_file->f_error = task->tk_status; + ClearPageUptodate(page); + SetPageError(page); + if (req->wb_file) + req->wb_file->f_error = task->tk_status; nfs_inode_remove_request(req); dprintk(", error = %d\n", task->tk_status); goto next; @@ -1329,9 +1308,9 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) end = 0; start = ~0; req = nfs_list_entry(head->next); - data->file = req->wb_file; + dentry = req->wb_dentry; + data->dentry = dentry; data->cred = req->wb_cred; - dentry = data->file->f_dentry; inode = dentry->d_inode; while (!list_empty(head)) { struct nfs_page *req; @@ -1364,7 +1343,6 @@ static int nfs_commit_list(struct list_head *head, int how) { struct rpc_message msg; - struct file *file; struct rpc_clnt *clnt; struct nfs_write_data *data; struct rpc_task *task; @@ -1384,8 +1362,7 @@ nfs_commit_list(struct list_head *head, int how) /* Set up the argument struct */ nfs_commit_rpcsetup(head, data); req = nfs_list_entry(data->pages.next); - file = req->wb_file; - clnt = NFS_CLIENT(file->f_dentry->d_inode); + clnt = NFS_CLIENT(req->wb_dentry->d_inode); rpc_init_task(task, clnt, nfs_commit_done, flags); task->tk_calldata = data; @@ -1422,7 +1399,7 @@ nfs_commit_done(struct rpc_task *task) struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; struct nfs_writeres *resp = &data->res; struct nfs_page *req; - struct dentry *dentry = data->file->f_dentry; + struct dentry *dentry = data->dentry; struct inode *inode = dentry->d_inode; dprintk("NFS: %4d nfs_commit_done (status %d)\n", @@ -1434,12 +1411,13 @@ nfs_commit_done(struct rpc_task *task) nfs_list_remove_request(req); dprintk("NFS: commit (%s/%s %d@%Ld)", - req->wb_file->f_dentry->d_parent->d_name.name, - req->wb_file->f_dentry->d_name.name, + req->wb_dentry->d_parent->d_name.name, + req->wb_dentry->d_name.name, req->wb_bytes, (long long)(page_offset(req->wb_page) + req->wb_offset)); if (task->tk_status < 0) { - req->wb_file->f_error = task->tk_status; + if (req->wb_file) + req->wb_file->f_error = task->tk_status; nfs_inode_remove_request(req); dprintk(", error = %d\n", task->tk_status); goto next; diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 53bfa0bea..6e98c1523 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -103,23 +103,6 @@ out: return exp; } - -/* - * Look up the device of the parent fs. - */ -static inline int -nfsd_parentdev(kdev_t *devp) -{ - struct super_block *sb; - - if (!(sb = get_super(*devp)) || !sb->s_root->d_covers) - return 0; - if (*devp == sb->s_root->d_covers->d_inode->i_dev) - return 0; - *devp = sb->s_root->d_covers->d_inode->i_dev; - return 1; -} - /* * Find the export entry for a given dentry. <gam3@acm.org> */ @@ -127,36 +110,13 @@ static svc_export * exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry) { svc_export *exp; - kdev_t xdev = dev; - struct dentry *xdentry = dentry; - struct dentry *ndentry = NULL; - if (clp == NULL || dentry == NULL) + if (clp == NULL) return NULL; - do { - xdev = dev; - do { - exp = clp->cl_export[EXPORT_HASH(xdev)]; - if (exp) - do { - ndentry = exp->ex_dentry; - if (ndentry == xdentry) { -#ifdef NFSD_PARANOIA -if (dev == xdev) - dprintk("nfsd: exp_parent submount over mount.\n"); -else - dprintk("nfsd: exp_parent found.\n"); -#endif - goto out; - } - } while (NULL != (exp = exp->ex_next)); - } while (nfsd_parentdev(&xdev)); - if (IS_ROOT(xdentry)) + for (exp = clp->cl_export[EXPORT_HASH(dev)]; exp; exp = exp->ex_next) + if (is_subdir(dentry, exp->ex_dentry)) break; - } while ((xdentry = xdentry->d_parent)); - exp = NULL; -out: return exp; } @@ -169,30 +129,15 @@ static svc_export * exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry) { svc_export *exp; - struct dentry *xdentry = dentry; - struct dentry *ndentry = NULL; - if (clp == NULL || dentry == NULL) + if (clp == NULL) return NULL; - exp = clp->cl_export[EXPORT_HASH(dev)]; - if (exp) - do { - ndentry = exp->ex_dentry; - if (ndentry) - while ((ndentry = ndentry->d_parent)) { - if (ndentry == xdentry) { -#ifdef NFSD_PARANOIA -dprintk("nfsd: exp_child mount under submount.\n"); -#endif - goto out; - } - if (IS_ROOT(ndentry)) - break; - } - } while (NULL != (exp = exp->ex_next)); - exp = NULL; -out: + for (exp = clp->cl_export[EXPORT_HASH(dev)]; exp; exp = exp->ex_next) { + struct dentry *ndentry = exp->ex_dentry; + if (ndentry && is_subdir(ndentry->d_parent, dentry)) + break; + } return exp; } @@ -279,10 +224,8 @@ exp_export(struct nfsctl_export *nxp) } /* Is this is a sub-export, must be a proper subset of FS */ if ((parent = exp_parent(clp, dev, dentry)) != NULL) { - if (dev == parent->ex_dev) { - dprintk("exp_export: sub-export not valid (Rule 2).\n"); - goto finish; - } + dprintk("exp_export: sub-export not valid (Rule 2).\n"); + goto finish; } err = -ENOMEM; diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 61ee94a3e..97acf317e 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -731,7 +731,7 @@ encode_entry(struct readdir_cd *cd, const char *name, dchild = dchild->d_parent; dchild = dget(dchild); } else - dchild = lookup_one(name, dget(dparent)); + dchild = lookup_one(name, dparent); if (IS_ERR(dchild)) goto noexec; if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode) diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 5c312b906..763970736 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -222,7 +222,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, if (isdotent(argp->name, argp->len)) goto done; fh_lock(dirfhp); - dchild = lookup_one(argp->name, dget(dirfhp->fh_dentry)); + dchild = lookup_one(argp->name, dirfhp->fh_dentry); if (IS_ERR(dchild)) { nfserr = nfserrno(PTR_ERR(dchild)); goto out_unlock; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 56da94aea..cb6134ca1 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -139,7 +139,8 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, } else { nd.mnt = NULL; nd.dentry = dget(dparent); - err = walk_name(name, 0, &nd); + nd.flags = 0; + err = walk_name(name, &nd); if (err) goto out_nfserr; /* @@ -838,7 +839,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, if (!resfhp->fh_dverified) { /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ fh_lock(fhp); - dchild = lookup_one(fname, dget(dentry)); + dchild = lookup_one(fname, dentry); err = PTR_ERR(dchild); if (IS_ERR(dchild)) goto out_nfserr; @@ -961,7 +962,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, /* * Compose the response file handle. */ - dchild = lookup_one(fname, dget(dentry)); + dchild = lookup_one(fname, dentry); err = PTR_ERR(dchild); if(IS_ERR(dchild)) goto out_nfserr; @@ -1108,7 +1109,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; fh_lock(fhp); dentry = fhp->fh_dentry; - dnew = lookup_one(fname, dget(dentry)); + dnew = lookup_one(fname, dentry); err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; @@ -1173,7 +1174,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, ddir = ffhp->fh_dentry; dirp = ddir->d_inode; - dnew = lookup_one(fname, dget(ddir)); + dnew = lookup_one(fname, ddir); err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; @@ -1238,7 +1239,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, goto out; double_down(&tdir->i_sem, &fdir->i_sem); - odentry = lookup_one(fname, dget(fdentry)); + odentry = lookup_one(fname, fdentry); err = PTR_ERR(odentry); if (IS_ERR(odentry)) goto out_nfserr; @@ -1247,7 +1248,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, if (!odentry->d_inode) goto out_dput_old; - ndentry = lookup_one(tname, dget(tdentry)); + ndentry = lookup_one(tname, tdentry); err = PTR_ERR(ndentry); if (IS_ERR(ndentry)) goto out_dput_old; @@ -1310,7 +1311,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, dentry = fhp->fh_dentry; dirp = dentry->d_inode; - rdentry = lookup_one(fname, dget(dentry)); + rdentry = lookup_one(fname, dentry); err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) goto out_nfserr; diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c index 058e3a6f4..238e5c61b 100644 --- a/fs/ntfs/fs.c +++ b/fs/ntfs/fs.c @@ -587,7 +587,7 @@ static struct inode_operations ntfs_dir_inode_operations = { #endif }; -static int ntfs_writepage(struct dentry *dentry, struct page *page) +static int ntfs_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,ntfs_get_block); } @@ -607,6 +607,7 @@ static int _ntfs_bmap(struct address_space *mapping, long block) struct address_space_operations ntfs_aops = { readpage: ntfs_readpage, writepage: ntfs_writepage, + sync_page: block_sync_page, prepare_write: ntfs_prepare_write, commit_write: generic_commit_write, bmap: _ntfs_bmap @@ -327,12 +327,10 @@ asmlinkage long sys_access(const char * filename, int mode) return res; } -/* MOUNT_REWRITE: pass &mnt to lookup_dentry */ asmlinkage long sys_chdir(const char * filename) { int error; - struct dentry *dentry, *tmp; - struct vfsmount *mnt = NULL, *tmp_mnt; + struct nameidata nd; char *name; lock_kernel(); @@ -342,27 +340,22 @@ asmlinkage long sys_chdir(const char * filename) if (IS_ERR(name)) goto out; - dentry = lookup_dentry(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY); + error = 0; + if (walk_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd)) + error = walk_name(name, &nd); putname(name); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) + if (error) goto out; - error = permission(dentry->d_inode,MAY_EXEC); + error = permission(nd.dentry->d_inode,MAY_EXEC); if (error) goto dput_and_out; - /* exchange dentries */ - tmp = current->fs->pwd; - tmp_mnt = current->fs->pwdmnt; - current->fs->pwd = dentry; - current->fs->pwdmnt = mnt; - dentry = tmp; - mnt = tmp_mnt; + set_fs_pwd(current->fs, nd.mnt, nd.dentry); dput_and_out: - mntput(mnt); - dput(dentry); + dput(nd.dentry); + mntput(nd.mnt); out: unlock_kernel(); return error; @@ -391,14 +384,8 @@ asmlinkage long sys_fchdir(unsigned int fd) lock_kernel(); error = permission(inode, MAY_EXEC); - if (!error) { - struct dentry *tmp = current->fs->pwd; - struct vfsmount *tmp_mnt = current->fs->pwdmnt; - current->fs->pwd = dget(dentry); - current->fs->pwdmnt = mntget(mnt); - mntput(tmp_mnt); - dput(tmp); - } + if (!error) + set_fs_pwd(current->fs, mnt, dentry); unlock_kernel(); out_putf: fput(file); @@ -406,12 +393,10 @@ out: return error; } -/* MOUNT_REWRITE: pass &mnt to lookup_dentry */ asmlinkage long sys_chroot(const char * filename) { int error; - struct dentry *dentry, *tmp; - struct vfsmount *mnt = NULL, *tmp_mnt; + struct nameidata nd; char *name; lock_kernel(); @@ -421,13 +406,14 @@ asmlinkage long sys_chroot(const char * filename) if (IS_ERR(name)) goto out; - dentry = lookup_dentry(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY); + walk_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | + LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd); + error = walk_name(name, &nd); putname(name); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) + if (error) goto out; - error = permission(dentry->d_inode,MAY_EXEC); + error = permission(nd.dentry->d_inode,MAY_EXEC); if (error) goto dput_and_out; @@ -435,18 +421,12 @@ asmlinkage long sys_chroot(const char * filename) if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; - /* exchange dentries */ - tmp = current->fs->root; - tmp_mnt = current->fs->rootmnt; - current->fs->root = dentry; - current->fs->rootmnt = mnt; - dentry = tmp; - mnt = tmp_mnt; + set_fs_root(current->fs, nd.mnt, nd.dentry); + set_fs_altroot(); error = 0; - dput_and_out: - mntput(mnt); - dput(dentry); + dput(nd.dentry); + mntput(nd.mnt); out: unlock_kernel(); return error; @@ -776,13 +756,20 @@ out: return error; } +inline void __put_unused_fd(struct files_struct *files, unsigned int fd) +{ + FD_CLR(fd, files->open_fds); + if (fd < files->next_fd) + files->next_fd = fd; +} + inline void put_unused_fd(unsigned int fd) { - write_lock(¤t->files->file_lock); - FD_CLR(fd, current->files->open_fds); - if (fd < current->files->next_fd) - current->files->next_fd = fd; - write_unlock(¤t->files->file_lock); + struct files_struct *files = current->files; + + write_lock(&files->file_lock); + __put_unused_fd(files, fd); + write_unlock(&files->file_lock); } asmlinkage long sys_open(const char * filename, int flags, int mode) @@ -868,13 +855,13 @@ int do_close(unsigned int fd, int release) error = -EBADF; write_lock(&files->file_lock); - filp = frip(fd); + filp = frip(files, fd); if (!filp) goto out_unlock; FD_CLR(fd, files->close_on_exec); - write_unlock(&files->file_lock); if (release) - put_unused_fd(fd); + __put_unused_fd(files, fd); + write_unlock(&files->file_lock); lock_kernel(); error = filp_close(filp, files); unlock_kernel(); diff --git a/fs/partitions/Config.in b/fs/partitions/Config.in index c7a39b9f4..de8681afa 100644 --- a/fs/partitions/Config.in +++ b/fs/partitions/Config.in @@ -14,6 +14,9 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then bool ' Alpha OSF partition support' CONFIG_OSF_PARTITION bool ' Amiga partition table support' CONFIG_AMIGA_PARTITION bool ' Atari partition table support' CONFIG_ATARI_PARTITION + if [ "$CONFIG_ARCH_S390" = "y" ]; then + bool ' IBM disk label and partition support' CONFIG_IBM_PARTITION + fi bool ' Macintosh partition map support' CONFIG_MAC_PARTITION bool ' PC BIOS (MSDOS partition tables) support' CONFIG_MSDOS_PARTITION if [ "$CONFIG_MSDOS_PARTITION" = "y" ]; then diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile index 2dc58c20d..4b41d2a75 100644 --- a/fs/partitions/Makefile +++ b/fs/partitions/Makefile @@ -22,6 +22,10 @@ ifeq ($(CONFIG_ATARI_PARTITION),y) O_OBJS += atari.o endif +ifeq ($(CONFIG_IBM_PARTITION),y) +O_OBJS += ibm.o +endif + ifeq ($(CONFIG_MAC_PARTITION),y) O_OBJS += mac.o endif @@ -46,4 +50,5 @@ ifeq ($(CONFIG_ULTRIX_PARTITION),y) O_OBJS += ultrix.o endif + include $(TOPDIR)/Rules.make diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index 561c87065..5717c4af9 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c @@ -485,9 +485,11 @@ int acorn_partition(struct gendisk *hd, kdev_t dev, if (r == 0) r = adfspart_check_POWERTEC(hd, dev, first_sector, first_part_minor); #endif - if (r < 0) - if (warn_no_part) printk(" unable to read boot sectors / partition sectors\n"); - else if (r) + if (r < 0) { + if (warn_no_part) + printk(" unable to read boot sectors / partition sectors\n"); + } else if (r) { printk("\n"); + } return r; } diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 836d43bf3..7f9ed2ba7 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -30,6 +30,7 @@ #include "osf.h" #include "sgi.h" #include "sun.h" +#include "ibm.h" #include "ultrix.h" extern void device_init(void); @@ -69,9 +70,17 @@ static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_s #ifdef CONFIG_ULTRIX_PARTITION ultrix_partition, #endif +#ifdef CONFIG_IBM_PARTITION + ibm_partition, +#endif NULL }; +#if defined CONFIG_BLK_DEV_LVM || defined CONFIG_BLK_DEV_LVM_MODULE +#include <linux/lvm.h> +void (*lvm_hd_name_ptr) (char *, int) = NULL; +#endif + /* * disk_name() is used by genhd.c and blkpg.c. * It formats the devicename of the indicated disk into @@ -98,6 +107,13 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) * This requires special handling here. */ switch (hd->major) { +#if defined CONFIG_BLK_DEV_LVM || defined CONFIG_BLK_DEV_LVM_MODULE + case LVM_BLK_MAJOR: + *buf = 0; + if ( lvm_hd_name_ptr != NULL) + (lvm_hd_name_ptr) ( buf, minor); + return buf; +#endif case IDE9_MAJOR: unit += 2; case IDE8_MAJOR: @@ -388,7 +404,7 @@ void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors, { if (!gdev) return; - grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); + grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); } void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) @@ -433,10 +449,6 @@ int __init partition_setup(void) #ifdef CONFIG_BLK_DEV_MD autodetect_raid(); #endif -#ifdef CONFIG_MD_BOOT - md_setup_drive(); -#endif - return 0; } diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c new file mode 100644 index 000000000..765bbc9f9 --- /dev/null +++ b/fs/partitions/ibm.c @@ -0,0 +1,122 @@ +/* + * File...........: linux/fs/partitions/ibm.c + * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + */ + +#include <linux/fs.h> +#include <linux/genhd.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/blk.h> + +#include <asm/ebcdic.h> +#include "../../drivers/s390/block/dasd_types.h" + +typedef enum { + ibm_partition_none = 0, + ibm_partition_lnx1 = 1, + ibm_partition_vol1 = 3, + ibm_partition_cms1 = 4 +} ibm_partition_t; + +static ibm_partition_t +get_partition_type ( char * type ) +{ + static char lnx[5]="LNX1"; + static char vol[5]="VOL1"; + static char cms[5]="CMS1"; + if ( ! strncmp ( lnx, "LNX1",4 ) ) { + ASCEBC(lnx,4); + ASCEBC(vol,4); + ASCEBC(cms,4); + } + if ( ! strncmp (type,lnx,4) || + ! strncmp (type,"LNX1",4) ) + return ibm_partition_lnx1; + if ( ! strncmp (type,vol,4) ) + return ibm_partition_vol1; + if ( ! strncmp (type,cms,4) ) + return ibm_partition_cms1; + return ibm_partition_none; +} + +void +ibm_partition (struct gendisk *hd, kdev_t dev) +{ + struct buffer_head *bh; + ibm_partition_t partition_type; + int di = MINOR(dev) >> PARTN_BITS; + char type[5] = {0,}; + char name[7] = {0,}; + if ( bh = bread( dev, + dasd_info[di]->sizes.label_block, + get_ptable_blocksize(dev) ) ) { + strncpy ( type,bh -> b_data, 4); + strncpy ( name,bh -> b_data + 4, 6); + } else { + return; + } + if ( (*(char *)bh -> b_data) & 0x80 ) { + EBCASC(name,6); + } + switch ( partition_type = get_partition_type(type) ) { + case ibm_partition_lnx1: + printk ( "(LNX1)/%6s:",name); + add_gd_partition( hd, MINOR(dev) + 1, + (dasd_info [di]->sizes.label_block + 1) << + dasd_info [di]->sizes.s2b_shift, + (dasd_info [di]->sizes.blocks - + dasd_info [di]->sizes.label_block - 1) << + dasd_info [di]->sizes.s2b_shift ); + break; + case ibm_partition_vol1: + printk ( "(VOL1)/%6s:",name); + break; + case ibm_partition_cms1: + printk ( "(CMS1)/%6s:",name); + if (* (((long *)bh->b_data) + 13) == 0) { + /* disk holds a CMS filesystem */ + add_gd_partition( hd, MINOR(dev) + 1, + (dasd_info [di]->sizes.label_block + 1) << + dasd_info [di]->sizes.s2b_shift, + (dasd_info [di]->sizes.blocks - + dasd_info [di]->sizes.label_block) << + dasd_info [di]->sizes.s2b_shift ); + printk ("(CMS)"); + } else { + /* disk is reserved minidisk */ + int offset = (*(((long *)bh->b_data) + 13)); + int size = (*(((long *)bh->b_data) + 7)) - 1 - + (*(((long *)bh->b_data) + 13)) * + ((*(((long *)bh->b_data) + 3)) >> 9); + add_gd_partition( hd, MINOR(dev) + 1, + offset << dasd_info [di]->sizes.s2b_shift, + size << dasd_info [di]->sizes.s2b_shift ); + printk ("(MDSK)"); + } + break; + case ibm_partition_none: + printk ( "(nonl)/ :"); +/* + printk ( "%d %d %d ", MINOR(dev) + 1, + (dasd_info [di]->sizes.label_block + 1) << + dasd_info [di]->sizes.s2b_shift, + (dasd_info [di]->sizes.blocks - + dasd_info [di]->sizes.label_block - 1) << + dasd_info [di]->sizes.s2b_shift ); +*/ + add_gd_partition( hd, MINOR(dev) + 1, + (dasd_info [di]->sizes.label_block + 1) << + dasd_info [di]->sizes.s2b_shift, + (dasd_info [di]->sizes.blocks - + dasd_info [di]->sizes.label_block - 1) << + dasd_info [di]->sizes.s2b_shift ); + break; + } + printk ( "\n" ); + bforget(bh); +} + diff --git a/fs/partitions/ibm.h b/fs/partitions/ibm.h new file mode 100644 index 000000000..35d01e06c --- /dev/null +++ b/fs/partitions/ibm.h @@ -0,0 +1 @@ +void ibm_partition (struct gendisk *hd, kdev_t dev); diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 21330f499..886e2f4c0 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -27,9 +27,9 @@ #include <linux/string.h> #include <linux/blk.h> -#ifdef CONFIG_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) #include <linux/ide.h> /* IDE xlate */ -#endif /* CONFIG_IDE */ +#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_HD) */ #include <asm/system.h> @@ -350,19 +350,19 @@ int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned char *data; int mask = (1 << hd->minor_shift) - 1; int sector_size = get_hardsect_size(dev) / 512; -#ifdef CONFIG_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) int tested_for_xlate = 0; read_mbr: -#endif /* CONFIG_IDE */ +#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_HD) */ if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) { if (warn_no_part) printk(" unable to read partition table\n"); return -1; } data = bh->b_data; -#ifdef CONFIG_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) check_table: -#endif /* CONFIG_IDE */ +#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_HD) */ /* Use bforget(), because we may have changed the disk geometry */ if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { bforget(bh); @@ -370,7 +370,7 @@ check_table: } p = (struct partition *) (0x1be + data); -#ifdef CONFIG_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) if (!tested_for_xlate++) { /* Do this only once per disk */ /* * Look for various forms of IDE disk geometry translation @@ -426,7 +426,7 @@ check_table: (void) ide_xlate_1024(dev, 2, heads, " [PTBL]"); } } -#endif /* CONFIG_IDE */ +#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_HD) */ /* Look for partitions in two passes: First find the primary partitions, and the DOS-type extended partitions. @@ -274,6 +274,7 @@ pipe_ioctl(struct inode *pino, struct file *filp, } } +/* No kernel lock held - fine */ static unsigned int pipe_poll(struct file *filp, poll_table *wait) { diff --git a/fs/proc/array.c b/fs/proc/array.c index 63a1d5828..6feabd36d 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -52,6 +52,7 @@ * : base.c too. */ +#include <linux/config.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/sched.h> @@ -269,6 +270,9 @@ int proc_pid_status(struct task_struct *task, char * buffer) { char * orig = buffer; struct mm_struct *mm = task->mm; +#if defined(CONFIG_ARCH_S390) + int line,len; +#endif buffer = task_name(task, buffer); buffer = task_state(task, buffer); @@ -276,6 +280,10 @@ int proc_pid_status(struct task_struct *task, char * buffer) buffer = task_mem(mm, buffer); buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); +#if defined(CONFIG_ARCH_S390) + for(line=0;(len=sprintf_regs(line,buffer,task,NULL,NULL))!=0;line++) + buffer+=len; +#endif return buffer - orig; } @@ -637,7 +645,7 @@ out: return retval; } -#ifdef __SMP__ +#ifdef CONFIG_SMP int proc_pid_cpu(struct task_struct *task, char * buffer) { int i, len; diff --git a/fs/proc/base.c b/fs/proc/base.c index 63bd4459b..ae3c36122 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -15,6 +15,7 @@ #include <asm/uaccess.h> +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/proc_fs.h> @@ -474,7 +475,7 @@ static struct pid_entry base_stuff[] = { E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO), -#ifdef __SMP__ +#ifdef CONFIG_SMP E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO), #endif E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO), @@ -800,7 +801,7 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) case PROC_PID_MAPS: inode->i_fop = &proc_maps_operations; break; -#ifdef __SMP__ +#ifdef CONFIG_SMP case PROC_PID_CPU: inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_cpu; diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index b16b9a9df..c1f126039 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -30,6 +30,7 @@ #include <linux/signal.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -284,14 +285,16 @@ static int kstat_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int i, len; - unsigned sum = 0; extern unsigned long total_forks; unsigned long jif = HZ_TO_STD(jiffies); +#if !defined(CONFIG_ARCH_S390) + unsigned sum = 0; for (i = 0 ; i < NR_IRQS ; i++) sum += kstat_irqs(i); +#endif -#ifdef __SMP__ +#ifdef CONFIG_SMP len = sprintf(page, "cpu %u %u %u %lu\n", kstat.cpu_user, @@ -314,9 +317,13 @@ static int kstat_read_proc(char *page, char **start, off_t off, "disk_rblk %u %u %u %u\n" "disk_wblk %u %u %u %u\n" "page %u %u\n" - "swap %u %u\n" +#if !defined(CONFIG_ARCH_S390) + "swap %u %u\n" "intr %u", #else + "swap %u %u\n", +#endif +#else len = sprintf(page, "cpu %u %u %u %lu\n" "disk %u %u %u %u\n" @@ -325,8 +332,12 @@ static int kstat_read_proc(char *page, char **start, off_t off, "disk_rblk %u %u %u %u\n" "disk_wblk %u %u %u %u\n" "page %u %u\n" - "swap %u %u\n" +#if !defined(CONFIG_ARCH_S390) + "swap %u %u\n" "intr %u", +#else + "swap %u %u\n" +#endif HZ_TO_STD(kstat.cpu_user), HZ_TO_STD(kstat.cpu_nice), HZ_TO_STD(kstat.cpu_system), @@ -346,10 +357,14 @@ static int kstat_read_proc(char *page, char **start, off_t off, kstat.pgpgin, kstat.pgpgout, kstat.pswpin, +#if !defined(CONFIG_ARCH_S390) kstat.pswpout, sum); - for (i = 0 ; i < NR_IRQS ; i++) - len += sprintf(page + len, " %u", kstat_irqs(i)); + for (i = 0 ; i < NR_IRQS ; i++) + len += sprintf(page + len, " %u", kstat_irqs(i)); +#else + kstat.pswpout); +#endif len += sprintf(page + len, "\nctxt %u\n" "btime %lu\n" @@ -389,6 +404,7 @@ static int partitions_read_proc(char *page, char **start, off_t off, return len; } +#if !defined(CONFIG_ARCH_S390) static int interrupts_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -400,6 +416,7 @@ static int interrupts_read_proc(char *page, char **start, off_t off, if (len<0) len = 0; return len; } +#endif static int filesystems_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -470,7 +487,10 @@ static int ds1286_read_proc(char *page, char **start, off_t off, static int locks_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { - int len = get_locks_status(page, start, off, count); + int len; + lock_kernel(); + len = get_locks_status(page, start, off, count); + unlock_kernel(); if (len < count) *eof = 1; return len; } @@ -575,7 +595,7 @@ static ssize_t read_profile(struct file *file, char *buf, static ssize_t write_profile(struct file * file, const char * buf, size_t count, loff_t *ppos) { -#ifdef __SMP__ +#ifdef CONFIG_SMP extern int setup_profiling_timer (unsigned int multiplier); if (count==sizeof(int)) { @@ -628,7 +648,9 @@ void __init proc_misc_init(void) {"stat", kstat_read_proc}, {"devices", devices_read_proc}, {"partitions", partitions_read_proc}, +#if !defined(CONFIG_ARCH_S390) {"interrupts", interrupts_read_proc}, +#endif {"filesystems", filesystems_read_proc}, {"dma", dma_read_proc}, {"ioports", ioports_read_proc}, diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index e241c938e..1d55d4989 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -93,7 +93,7 @@ static int tty_drivers_read_proc(char *page, char **start, off_t off, *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } @@ -123,7 +123,7 @@ static int tty_ldiscs_read_proc(char *page, char **start, off_t off, *eof = 1; if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index c6511354b..e54d32914 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -410,7 +410,7 @@ static void qnx4_put_super(struct super_block *sb) return; } -static int qnx4_writepage(struct dentry *dentry, struct page *page) +static int qnx4_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,qnx4_get_block); } @@ -430,6 +430,7 @@ static int qnx4_bmap(struct address_space *mapping, long block) struct address_space_operations qnx4_aops = { readpage: qnx4_readpage, writepage: qnx4_writepage, + sync_page: block_sync_page, prepare_write: qnx4_prepare_write, commit_write: generic_commit_write, bmap: qnx4_bmap diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index a25200b14..5be9b240f 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -171,10 +171,6 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry) goto end_rmdir; } #endif - if (!d_unhashed(dentry)) { - retval = -EBUSY; - goto end_rmdir; - } if (inode->i_nlink != 2) { QNX4DEBUG(("empty directory has nlink!=2 (%d)\n", inode->i_nlink)); } diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index e218051f3..568b8e6bd 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -76,7 +76,7 @@ static int ramfs_readpage(struct dentry *dentry, struct page * page) * Writing: just make sure the page gets marked dirty, so that * the page stealer won't grab it. */ -static int ramfs_writepage(struct dentry * dentry, struct page *page) +static int ramfs_writepage(struct file *file, struct dentry * dentry, struct page *page) { SetPageDirty(page); return 0; diff --git a/fs/readdir.c b/fs/readdir.c index 4bf222288..e6256636e 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -22,7 +22,11 @@ int vfs_readdir(struct file *file, if (!file->f_op || !file->f_op->readdir) goto out; down(&inode->i_sem); - res = file->f_op->readdir(file, buf, filler); + down(&inode->i_zombie); + res = -ENOENT; + if (!IS_DEADDIR(inode)) + res = file->f_op->readdir(file, buf, filler); + up(&inode->i_zombie); up(&inode->i_sem); out: return res; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 63d5a58ab..94a8f61aa 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -506,7 +506,8 @@ romfs_read_inode(struct inode *i) break; case 3: i->i_op = &page_symlink_inode_operations; - i->i_mode = S_IRWXUGO; + i->i_data.a_ops = &romfs_aops; + i->i_mode = ino | S_IRWXUGO; break; default: /* depending on MBZ for sock/fifos */ diff --git a/fs/select.c b/fs/select.c index 33e54a9fa..86c2793d7 100644 --- a/fs/select.c +++ b/fs/select.c @@ -194,7 +194,6 @@ int do_select(int n, fd_set_bits *fds, long *timeout) retval = 0; for (;;) { set_current_state(TASK_INTERRUPTIBLE); - lock_kernel(); for (i = 0 ; i < n; i++) { unsigned long bit = BIT(i); unsigned long mask; @@ -227,7 +226,6 @@ int do_select(int n, fd_set_bits *fds, long *timeout) wait = NULL; } } - unlock_kernel(); wait = NULL; if (retval || !__timeout || signal_pending(current)) break; @@ -462,9 +460,7 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout) goto out_fds1; } - lock_kernel(); fdcount = do_poll(nfds, nchunks, nleft, fds, wait, timeout); - unlock_kernel(); /* OK, now copy the revents fields back to user space. */ for(i=0; i < nchunks; i++) diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 12e2bf295..67920a252 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -167,7 +167,7 @@ printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result); * We are called with the page locked and the caller unlocks. */ static int -smb_writepage(struct dentry *dentry, struct page *page) +smb_writepage(struct file *file, struct dentry *dentry, struct page *page) { struct inode *inode = dentry->d_inode; unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; @@ -25,7 +25,7 @@ do_revalidate(struct dentry *dentry) } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) /* * For backward compatibility? Maybe this should be moved @@ -115,7 +115,7 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf) } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) /* * For backward compatibility? Maybe this should be moved * into arch/i386 instead? @@ -161,7 +161,7 @@ asmlinkage long sys_newstat(char * filename, struct stat * statbuf) return error; } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) /* * For backward compatibility? Maybe this should be moved @@ -209,7 +209,7 @@ asmlinkage long sys_newlstat(char * filename, struct stat * statbuf) return error; } -#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) +#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) /* * For backward compatibility? Maybe this should be moved diff --git a/fs/super.c b/fs/super.c index c7848eb90..141bde7d8 100644 --- a/fs/super.c +++ b/fs/super.c @@ -76,6 +76,13 @@ LIST_HEAD(super_blocks); static struct file_system_type *file_systems = NULL; static spinlock_t file_systems_lock = SPIN_LOCK_UNLOCKED; +/* WARNING: This can be used only if we _already_ own a reference */ +static void get_filesystem(struct file_system_type *fs) +{ + if (fs->owner) + __MOD_INC_USE_COUNT(fs->owner); +} + static void put_filesystem(struct file_system_type *fs) { if (fs->owner) @@ -96,10 +103,10 @@ static struct file_system_type **find_filesystem(const char *name) * @fs: the file system structure * * Adds the file system passed to the list of file systems the kernel - * is aware of for by mount and other syscalls. Returns 0 on success, + * is aware of for mount and other syscalls. Returns 0 on success, * or a negative errno code on an error. * - * The file_system_type that is passed is linked into the kernel + * The &struct file_system_type that is passed is linked into the kernel * structures and must not be freed until the file system has been * unregistered. */ @@ -131,8 +138,8 @@ int register_filesystem(struct file_system_type * fs) * with the kernel. An error is returned if the file system is not found. * Zero is returned on a success. * - * Once this function has returned the file_system_type structure may be - * freed or reused. + * Once this function has returned the &struct file_system_type structure + * may be freed or reused. */ int unregister_filesystem(struct file_system_type * fs) @@ -269,79 +276,58 @@ static struct file_system_type *get_fs_type(const char *name) return fs; } -struct vfsmount *vfsmntlist = NULL; -static struct vfsmount *vfsmnttail = NULL, *mru_vfsmnt = NULL; +static LIST_HEAD(vfsmntlist); static struct vfsmount *add_vfsmnt(struct super_block *sb, const char *dev_name, const char *dir_name) { - struct vfsmount *lptr; + struct vfsmount *mnt; char *name; - lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL); - if (!lptr) + mnt = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL); + if (!mnt) goto out; - memset(lptr, 0, sizeof(struct vfsmount)); + memset(mnt, 0, sizeof(struct vfsmount)); - lptr->mnt_sb = sb; - lptr->mnt_dev = sb->s_dev; + mnt->mnt_sb = sb; + mnt->mnt_dev = sb->s_dev; /* N.B. Is it really OK to have a vfsmount without names? */ if (dev_name) { name = (char *) kmalloc(strlen(dev_name)+1, GFP_KERNEL); if (name) { strcpy(name, dev_name); - lptr->mnt_devname = name; + mnt->mnt_devname = name; } } if (dir_name) { name = (char *) kmalloc(strlen(dir_name)+1, GFP_KERNEL); if (name) { strcpy(name, dir_name); - lptr->mnt_dirname = name; + mnt->mnt_dirname = name; } } - if (vfsmntlist == (struct vfsmount *)NULL) { - vfsmntlist = vfsmnttail = lptr; - } else { - vfsmnttail->mnt_next = lptr; - vfsmnttail = lptr; - } + list_add(&mnt->mnt_list, vfsmntlist.prev); out: - return lptr; + return mnt; } void remove_vfsmnt(kdev_t dev) { - struct vfsmount *lptr, *tofree; + struct list_head *p, *next; - if (vfsmntlist == NULL) - return; - lptr = vfsmntlist; - if (lptr->mnt_dev == dev) { - tofree = lptr; - vfsmntlist = lptr->mnt_next; - if (vfsmnttail->mnt_dev == dev) - vfsmnttail = vfsmntlist; - } else { - while (lptr->mnt_next != NULL) { - if (lptr->mnt_next->mnt_dev == dev) - break; - lptr = lptr->mnt_next; - } - tofree = lptr->mnt_next; - if (tofree == NULL) - return; - lptr->mnt_next = lptr->mnt_next->mnt_next; - if (vfsmnttail->mnt_dev == dev) - vfsmnttail = lptr; + for (p = vfsmntlist.next; p != &vfsmntlist; p = next) { + struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list); + + next = p->next; + if (mnt->mnt_dev != dev) + continue; + list_del(&mnt->mnt_list); + kfree(mnt->mnt_devname); + kfree(mnt->mnt_dirname); + kfree(mnt); } - if (tofree == mru_vfsmnt) - mru_vfsmnt = NULL; - kfree(tofree->mnt_devname); - kfree(tofree->mnt_dirname); - kfree_s(tofree, sizeof(struct vfsmount)); } static struct proc_fs_info { @@ -378,7 +364,7 @@ static struct proc_nfs_info { int get_filesystem_info( char *buf ) { - struct vfsmount *tmp; + struct list_head *p; struct proc_fs_info *fs_infop; struct proc_nfs_info *nfs_infop; struct nfs_server *nfss; @@ -386,7 +372,9 @@ int get_filesystem_info( char *buf ) char *path,*buffer = (char *) __get_free_page(GFP_KERNEL); if (!buffer) return 0; - for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160; tmp = tmp->mnt_next) { + for (p = vfsmntlist.next; p!=&vfsmntlist && len < PAGE_SIZE - 160; + p = p->next) { + struct vfsmount *tmp = list_entry(p, struct vfsmount, mnt_list); if (!tmp->mnt_sb || !tmp->mnt_sb->s_root) continue; path = d_path(tmp->mnt_sb->s_root, tmp, buffer, PAGE_SIZE); @@ -459,7 +447,7 @@ int get_filesystem_info( char *buf ) * @sb: superblock to wait on * * Waits for a superblock to become unlocked and then returns. It does - * not take the lock. This is an internal function. See wait_on_super. + * not take the lock. This is an internal function. See wait_on_super(). */ void __wait_on_super(struct super_block * sb) @@ -495,23 +483,20 @@ void sync_supers(kdev_t dev) continue; if (!sb->s_dirt) continue; - /* N.B. Should lock the superblock while writing */ - wait_on_super(sb); - if (!sb->s_dev || !sb->s_dirt) - continue; - if (dev && (dev != sb->s_dev)) - continue; - if (sb->s_op && sb->s_op->write_super) - sb->s_op->write_super(sb); + lock_super(sb); + if (sb->s_dev && sb->s_dirt && (!dev || dev == sb->s_dev)) + if (sb->s_op && sb->s_op->write_super) + sb->s_op->write_super(sb); + unlock_super(sb); } } /** * get_super - get the superblock of a device - * @dev: device to get the super block for + * @dev: device to get the superblock for * * Scans the superblock list and finds the superblock of the file system - * mounted on the device given. NULL is returned if no match is found. + * mounted on the device given. %NULL is returned if no match is found. */ struct super_block * get_super(kdev_t dev) @@ -561,10 +546,10 @@ out: /** * get_empty_super - find empty superblocks * - * Find a super_block with no device assigned. A free superblock is + * Find a superblock with no device assigned. A free superblock is * found and returned. If neccessary new superblocks are allocated. - * NULL is returned if there are insufficient resources to complete - * the request + * %NULL is returned if there are insufficient resources to complete + * the request. */ struct super_block *get_empty_super(void) @@ -659,6 +644,165 @@ void put_unnamed_dev(kdev_t dev) kdevname(dev)); } +static struct super_block *get_sb_bdev(struct file_system_type *fs_type, + char *dev_name, int flags, void * data) +{ + struct dentry *dentry; + struct inode *inode; + struct block_device *bdev; + struct block_device_operations *bdops; + struct super_block * sb; + kdev_t dev; + int error; + /* What device it is? */ + if (!dev_name || !*dev_name) + return ERR_PTR(-EINVAL); + dentry = lookup_dentry(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE); + if (IS_ERR(dentry)) + return (struct super_block *)dentry; + inode = dentry->d_inode; + error = -ENOTBLK; + if (!S_ISBLK(inode->i_mode)) + goto out; + error = -EACCES; + if (IS_NODEV(inode)) + goto out; + bdev = inode->i_bdev; + bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) ); + if (bdops) bdev->bd_op = bdops; + /* Done with lookups, semaphore down */ + down(&mount_sem); + dev = to_kdev_t(bdev->bd_dev); + check_disk_change(dev); + error = -EACCES; + if (!(flags & MS_RDONLY) && is_read_only(dev)) + goto out; + sb = get_super(dev); + if (sb) { + error = -EBUSY; + goto out; + /* MOUNT_REWRITE: the following should be used + if (fs_type == sb->s_type) { + dput(dentry); + return sb; + } + */ + } else { + mode_t mode = FMODE_READ; /* we always need it ;-) */ + if (!(flags & MS_RDONLY)) + mode |= FMODE_WRITE; + error = blkdev_get(bdev, mode, 0, BDEV_FS); + if (error) + goto out; + error = -EINVAL; + sb = read_super(dev, bdev, fs_type, flags, data, 0); + if (sb) { + get_filesystem(fs_type); + dput(dentry); + return sb; + } + blkdev_put(bdev, BDEV_FS); + } +out: + dput(dentry); + up(&mount_sem); + return ERR_PTR(error); +} + +static struct super_block *get_sb_nodev(struct file_system_type *fs_type, + int flags, void * data) +{ + kdev_t dev; + int error = -EMFILE; + down(&mount_sem); + dev = get_unnamed_dev(); + if (dev) { + struct super_block * sb; + error = -EINVAL; + sb = read_super(dev, NULL, fs_type, flags, data, 0); + if (sb) { + get_filesystem(fs_type); + return sb; + } + put_unnamed_dev(dev); + } + up(&mount_sem); + return ERR_PTR(error); +} + +static struct block_device *kill_super(struct super_block *sb, int umount_root) +{ + struct block_device *bdev; + kdev_t dev; + lock_super(sb); + if (sb->s_op) { + if (sb->s_op->write_super && sb->s_dirt) + sb->s_op->write_super(sb); + if (sb->s_op->put_super) + sb->s_op->put_super(sb); + } + + /* Forget any remaining inodes */ + if (invalidate_inodes(sb)) { + printk("VFS: Busy inodes after unmount. " + "Self-destruct in 5 seconds. Have a nice day...\n"); + } + + dev = sb->s_dev; + sb->s_dev = 0; /* Free the superblock */ + bdev = sb->s_bdev; + sb->s_bdev = NULL; + put_filesystem(sb->s_type); + sb->s_type = NULL; + unlock_super(sb); + if (umount_root) { + /* special: the old device driver is going to be + a ramdisk and the point of this call is to free its + protected memory (even if dirty). */ + destroy_buffers(dev); + } + if (bdev) { + blkdev_put(bdev, BDEV_FS); + bdput(bdev); + } else + put_unnamed_dev(dev); + return bdev; +} + +/* + * Alters the mount flags of a mounted file system. Only the mount point + * is used as a reference - file system type and the device are ignored. + */ + +static int do_remount_sb(struct super_block *sb, int flags, char *data) +{ + int retval; + + if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev)) + return -EACCES; + /*flags |= MS_RDONLY;*/ + /* If we are remounting RDONLY, make sure there are no rw files open */ + if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) + if (!fs_may_remount_ro(sb)) + return -EBUSY; + if (sb->s_op && sb->s_op->remount_fs) { + lock_super(sb); + retval = sb->s_op->remount_fs(sb, &flags, data); + unlock_super(sb); + if (retval) + return retval; + } + sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); + + /* + * We can't invalidate inodes as we can loose data when remounting + * (someone might manage to alter data while we are waiting in lock_super() + * or in foo_remount_fs())) + */ + + return 0; +} + static int d_umount(struct super_block * sb) { struct dentry * root = sb->s_root; @@ -747,32 +891,8 @@ static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags) retval = d_umount(sb); if (retval) goto out; - - if (sb->s_op) { - if (sb->s_op->write_super && sb->s_dirt) - sb->s_op->write_super(sb); - } - - lock_super(sb); - if (sb->s_op) { - if (sb->s_op->put_super) - sb->s_op->put_super(sb); - } - - /* Forget any remaining inodes */ - if (invalidate_inodes(sb)) { - printk("VFS: Busy inodes after unmount. " - "Self-destruct in 5 seconds. Have a nice day...\n"); - } - - sb->s_dev = 0; /* Free the superblock */ - bdev = sb->s_bdev; - sb->s_bdev = NULL; - put_filesystem(sb->s_type); - sb->s_type = NULL; - unlock_super(sb); - remove_vfsmnt(dev); + bdev = kill_super(sb, unmount_root); return bdev; @@ -796,15 +916,8 @@ static int umount_dev(kdev_t dev, int flags) bdev = do_umount(dev, 0, flags); if (IS_ERR(bdev)) retval = PTR_ERR(bdev); - else { + else retval = 0; - if (bdev) { - blkdev_put(bdev, BDEV_FS); - bdput(bdev); - } else { - put_unnamed_dev(dev); - } - } up(&mount_sem); out: return retval; @@ -877,170 +990,19 @@ int fs_may_mount(kdev_t dev) } /* - * do_mount() does the actual mounting after sys_mount has done the ugly - * parameter parsing. When enough time has gone by, and everything uses the - * new mount() parameters, sys_mount() can then be cleaned up. - * - * We cannot mount a filesystem if it has active, used, or dirty inodes. - * We also have to flush all inode-data for this device, as the new mount - * might need new info. - * - * [21-Mar-97] T.Schoebel-Theuer: Now this can be overridden when - * supplying a leading "!" before the dir_name, allowing "stacks" of - * mounted filesystems. The stacking will only influence any pathname lookups - * _after_ the mount, but open file descriptors or working directories that - * are now covered remain valid. For example, when you overmount /home, any - * process with old cwd /home/joe will continue to use the old versions, - * as long as relative paths are used, but absolute paths like /home/joe/xxx - * will go to the new "top of stack" version. In general, crossing a - * mount point will always go to the top of stack element. - * Anyone using this new feature must know what he/she is doing. + * change filesystem flags. dir should be a physical root of filesystem. + * If you've mounted a non-root directory somewhere and want to do remount + * on it - tough luck. */ -static int do_mount(struct block_device *bdev, const char *dev_name, - const char *dir_name, const char * type, int flags, void * data) -{ - kdev_t dev; - struct dentry * dir_d; - struct super_block * sb; - struct vfsmount *vfsmnt; - struct file_system_type *fs_type; - int error; - - if (bdev) { - mode_t mode = FMODE_READ; /* we always need it ;-) */ - if (!(flags & MS_RDONLY)) - mode |= FMODE_WRITE; - dev = to_kdev_t(bdev->bd_dev); - error = blkdev_get(bdev, mode, 0, BDEV_FS); - if (error) - return error; - } else { - dev = get_unnamed_dev(); - if (!dev) - return -EMFILE; /* huh? */ - } - - error = -EACCES; - if (!(flags & MS_RDONLY) && dev && is_read_only(dev)) - goto out; - - /* - * Do the lookup first to force automounting. - */ - dir_d = lookup_dentry(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE); - error = PTR_ERR(dir_d); - if (IS_ERR(dir_d)) - goto out; - - down(&mount_sem); - error = -ENOTDIR; - if (!S_ISDIR(dir_d->d_inode->i_mode)) - goto dput_and_out; - - error = -EBUSY; - if (dir_d->d_covers != dir_d) - goto dput_and_out; - - error = -EINVAL; - if (!dev) - goto dput_and_out; - check_disk_change(dev); - sb = get_super(dev); - if (sb) { - /* Already mounted */ - error = -EBUSY; - goto dput_and_out; - } - - fs_type = get_fs_type(type); - if (!fs_type) { - printk("VFS: on device %s: get_fs_type(%s) failed\n", - kdevname(dev), type); - goto dput_and_out; - } - - sb = read_super(dev, bdev, fs_type, flags, data, 0); - if (!sb) - goto fsput_and_out; - - /* - * We may have slept while reading the super block, - * so we check afterwards whether it's safe to mount. - */ - error = -EBUSY; - if (!fs_may_mount(dev)) - goto bdput_and_out; - - error = -ENOMEM; - vfsmnt = add_vfsmnt(sb, dev_name, dir_name); - if (vfsmnt) { - d_mount(dget(dir_d), sb->s_root); - dput(dir_d); - up(&mount_sem); - return 0; - } - -bdput_and_out: - /* FIXME: ->put_super() is needed here */ - sb->s_bdev = NULL; - sb->s_dev = 0; - sb->s_type = NULL; - if (bdev) - bdput(bdev); -fsput_and_out: - put_filesystem(fs_type); -dput_and_out: - dput(dir_d); - up(&mount_sem); -out: - if (bdev) - blkdev_put(bdev, BDEV_FS); - else - put_unnamed_dev(dev); - return error; -} - - -/* - * Alters the mount flags of a mounted file system. Only the mount point - * is used as a reference - file system type and the device are ignored. - */ - -static int do_remount_sb(struct super_block *sb, int flags, char *data) -{ - int retval; - - if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev)) - return -EACCES; - /*flags |= MS_RDONLY;*/ - /* If we are remounting RDONLY, make sure there are no rw files open */ - if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) - if (!fs_may_remount_ro(sb)) - return -EBUSY; - if (sb->s_op && sb->s_op->remount_fs) { - lock_super(sb); - retval = sb->s_op->remount_fs(sb, &flags, data); - unlock_super(sb); - if (retval) - return retval; - } - sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); - - /* - * We can't invalidate inodes as we can loose data when remounting - * (someone might manage to alter data while we are waiting in lock_super() - * or in foo_remount_fs())) - */ - - return 0; -} - static int do_remount(const char *dir,int flags,char *data) { struct dentry *dentry; int retval; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + dentry = lookup_dentry(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE); retval = PTR_ERR(dentry); if (!IS_ERR(dentry)) { @@ -1111,9 +1073,9 @@ long do_sys_mount(char * dev_name, char * dir_name, char *type_page, unsigned long new_flags, void *data_page) { struct file_system_type * fstype; - struct dentry * dentry = NULL; - struct inode * inode = NULL; - struct block_device *bdev = NULL; + struct dentry * dir_d; + struct vfsmount *mnt; + struct super_block *sb; int retval; unsigned long flags = 0; @@ -1126,59 +1088,84 @@ long do_sys_mount(char * dev_name, char * dir_name, char *type_page, if (dev_name && !memchr(dev_name, 0, PAGE_SIZE)) return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; + /* OK, looks good, now let's see what do they want */ - if ((new_flags & - (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { - retval = do_remount(dir_name, - new_flags & ~MS_MGC_MSK & ~MS_REMOUNT, + /* just change the flags? - capabilities are checked in do_remount() */ + if ((new_flags & (MS_MGC_MSK|MS_REMOUNT)) == (MS_MGC_VAL|MS_REMOUNT)) + return do_remount(dir_name, new_flags&~(MS_MGC_MSK|MS_REMOUNT), (char *) data_page); - goto out; - } + if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) + flags = new_flags & ~MS_MGC_MSK; + + /* loopback mount? This is special - requires fewer capabilities */ + /* MOUNT_REWRITE: ... and is yet to be merged */ + + /* for the rest we _really_ need capabilities... */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* ... filesystem driver... */ fstype = get_fs_type(type_page); - retval = -ENODEV; if (!fstype) - goto out; + return -ENODEV; - if (fstype->fs_flags & FS_REQUIRES_DEV) { - struct block_device_operations *bdops; + /* ... and mountpoint. Do the lookup first to force automounting. */ + dir_d = lookup_dentry(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE); + retval = PTR_ERR(dir_d); + if (IS_ERR(dir_d)) + goto fs_out; - retval = -EINVAL; - if (!dev_name || !*dev_name) - goto fs_out; - dentry = lookup_dentry(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE); - retval = PTR_ERR(dentry); - if (IS_ERR(dentry)) - goto fs_out; - - inode = dentry->d_inode; - retval = -ENOTBLK; - if (!S_ISBLK(inode->i_mode)) - goto dput_and_out; - - retval = -EACCES; - if (IS_NODEV(inode)) - goto dput_and_out; - - bdev = inode->i_bdev; - bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) ); - if (bdops) bdev->bd_op = bdops; - } + /* get superblock, locks mount_sem on success */ + if (fstype->fs_flags & FS_REQUIRES_DEV) + sb = get_sb_bdev(fstype, dev_name,flags, data_page); + else + sb = get_sb_nodev(fstype, flags, data_page); - if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) - flags = new_flags & ~MS_MGC_MSK; + retval = PTR_ERR(sb); + if (IS_ERR(sb)) + goto dput_out; - retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags, - data_page); + retval = -ENOENT; + if (d_unhashed(dir_d)) + goto fail; -dput_and_out: - dput(dentry); + retval = -ENOTDIR; + if (!S_ISDIR(dir_d->d_inode->i_mode)) + goto fail; + + retval = -EBUSY; + if (dir_d->d_covers != dir_d) + goto fail; + + /* + * We may have slept while reading the super block, + * so we check afterwards whether it's safe to mount. + */ + retval = -EBUSY; + if (!fs_may_mount(sb->s_dev)) + goto fail; + + retval = -ENOMEM; + mnt = add_vfsmnt(sb, dev_name, dir_name); + if (!mnt) + goto fail; + d_mount(dget(dir_d), sb->s_root); + + retval = 0; +unlock_out: + up(&mount_sem); +dput_out: + dput(dir_d); fs_out: put_filesystem(fstype); -out: return retval; + +fail: + dput(sb->s_root); + sb->s_root = NULL; + kill_super(sb, 0); + goto unlock_out; } asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, @@ -1242,39 +1229,38 @@ void __init mount_root(void) int path_start = -1; #ifdef CONFIG_ROOT_NFS - if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { - ROOT_DEV = 0; - if ((fs_type = get_fs_type("nfs"))) { - sb = get_empty_super(); /* "can't fail" */ - sb->s_dev = get_unnamed_dev(); - sb->s_bdev = NULL; - sb->s_flags = root_mountflags; - sema_init(&sb->s_vfs_rename_sem,1); - sema_init(&sb->s_nfsd_free_path_sem,1); - vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); - if (vfsmnt) { - if (nfs_root_mount(sb) >= 0) { - sb->s_dirt = 0; - sb->s_type = fs_type; - current->fs->root = dget(sb->s_root); - current->fs->rootmnt = mntget(vfsmnt); - current->fs->pwd = dget(sb->s_root); - current->fs->pwdmnt = mntget(vfsmnt); - ROOT_DEV = sb->s_dev; - printk (KERN_NOTICE "VFS: Mounted root (NFS filesystem)%s.\n", (sb->s_flags & MS_RDONLY) ? " readonly" : ""); - return; - } - remove_vfsmnt(sb->s_dev); - } - put_unnamed_dev(sb->s_dev); - sb->s_dev = 0; - put_filesystem(fs_type); - } - if (!ROOT_DEV) { - printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); - ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); - } - } + void *data; + if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) + goto skip_nfs; + fs_type = get_fs_type("nfs"); + if (!fs_type) + goto no_nfs; + ROOT_DEV = get_unnamed_dev(); + if (!ROOT_DEV) + /* + * Your /linuxrc sucks worse than MSExchange - that's the + * only way you could run out of anon devices at that point. + */ + goto no_anon; + data = nfs_root_data(); + if (!data) + goto no_server; + sb = read_super(ROOT_DEV, NULL, fs_type, root_mountflags, data, 1); + if (sb) + /* + * We _can_ fail there, but if that will happen we have no + * chance anyway (no memory for vfsmnt and we _will_ need it, + * no matter which fs we try to mount). + */ + goto mount_it; +no_server: + put_unnamed_dev(ROOT_DEV); +no_anon: + put_filesystem(fs_type); +no_nfs: + printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); + ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); +skip_nfs: #endif #ifdef CONFIG_BLK_DEV_FD @@ -1369,11 +1355,8 @@ void __init mount_root(void) kdevname(ROOT_DEV)); mount_it: - sb->s_flags = root_mountflags; - current->fs->root = dget(sb->s_root); - current->fs->rootmnt = mntget(vfsmnt); - current->fs->pwd = dget(sb->s_root); - current->fs->pwdmnt = mntget(vfsmnt); + set_fs_root(current->fs, vfsmnt, sb->s_root); + set_fs_pwd(current->fs, vfsmnt, sb->s_root); printk ("VFS: Mounted root (%s filesystem)%s.\n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); @@ -1388,7 +1371,8 @@ mount_it: } else vfsmnt = add_vfsmnt (sb, "/dev/root", "/"); if (vfsmnt) { - bdput(bdev); /* sb holds a reference */ + if (bdev) + bdput(bdev); /* sb holds a reference */ return; } panic("VFS: add_vfsmnt failed for root fs"); @@ -1402,27 +1386,22 @@ static void chroot_fs_refs(struct dentry *old_root, { struct task_struct *p; + /* We can't afford dput() blocking under the tasklist_lock */ + mntget(old_rootmnt); + dget(old_root); + read_lock(&tasklist_lock); for_each_task(p) { if (!p->fs) continue; - if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) { - p->fs->root = dget(new_root); - p->fs->rootmnt = mntget(new_rootmnt); - mntput(old_rootmnt); - dput(old_root); - printk(KERN_DEBUG "chroot_fs_refs: changed root of " - "process %d\n",p->pid); - } - if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt) { - p->fs->pwd = dget(new_root); - p->fs->pwdmnt = mntget(new_rootmnt); - mntput(old_rootmnt); - dput(old_root); - printk(KERN_DEBUG "chroot_fs_refs: changed cwd of " - "process %d\n",p->pid); - } + if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) + set_fs_root(p->fs, new_rootmnt, new_root); + if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt) + set_fs_pwd(p->fs, new_rootmnt, new_root); } read_unlock(&tasklist_lock); + + dput(old_root); + mntput(old_rootmnt); } /* @@ -1570,14 +1549,6 @@ int __init change_root(kdev_t new_root_dev,const char *put_old) bdev = do_umount(old_root_dev,1, 0); if (!IS_ERR(bdev)) { printk("okay\n"); - /* special: the old device driver is going to be - a ramdisk and the point of this call is to free its - protected memory (even if dirty). */ - destroy_buffers(old_root_dev); - if (bdev) { - blkdev_put(bdev, BDEV_FS); - bdput(bdev); - } return 0; } printk(KERN_ERR "error %ld\n",PTR_ERR(bdev)); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index b6396ff04..bdb65a005 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -516,7 +516,6 @@ static struct super_block *sysv_read_super(struct super_block *sb, /* This is only called on sync() and umount(), when s_dirt=1. */ static void sysv_write_super(struct super_block *sb) { - lock_super(sb); if (buffer_dirty(sb->sv_bh1) || buffer_dirty(sb->sv_bh2)) { /* If we are going to write out the super block, then attach current time stamp. @@ -534,7 +533,6 @@ static void sysv_write_super(struct super_block *sb) mark_buffer_dirty(sb->sv_bh2, 1); } sb->s_dirt = 0; - unlock_super(sb); } static void sysv_put_super(struct super_block *sb) @@ -941,7 +939,7 @@ struct buffer_head *sysv_file_bread(struct inode *inode, int block, int create) return NULL; } -static int sysv_writepage(struct dentry *dentry, struct page *page) +static int sysv_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,sysv_get_block); } @@ -960,6 +958,7 @@ static int sysv_bmap(struct address_space *mapping, long block) struct address_space_operations sysv_aops = { readpage: sysv_readpage, writepage: sysv_writepage, + sync_page: block_sync_page, prepare_write: sysv_prepare_write, commit_write: generic_commit_write, bmap: sysv_bmap diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index 6a7fbf34b..0abffaac6 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -389,10 +389,6 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry) retval = -ENOTEMPTY; goto end_rmdir; } - if (!d_unhashed(dentry)) { - retval = -EBUSY; - goto end_rmdir; - } if (inode->i_nlink != 2) printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink); de->inode = 0; @@ -552,9 +548,6 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, } if (S_ISDIR(old_inode->i_mode)) { if (new_inode) { - retval = -EBUSY; - if (!d_unhashed(new_dentry)) - goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_inode)) goto end_rename; diff --git a/fs/udf/file.c b/fs/udf/file.c index cbaf77929..ebb6fda24 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -65,7 +65,7 @@ static int udf_adinicb_readpage(struct dentry *dentry, struct page * page) return 0; } -static int udf_adinicb_writepage(struct dentry *dentry, struct page *page) +static int udf_adinicb_writepage(struct file *file, struct dentry *dentry, struct page *page) { struct inode *inode = (struct inode *)page->mapping->host; @@ -118,6 +118,7 @@ static int udf_adinicb_commit_write(struct file *file, struct page *page, unsign struct address_space_operations udf_adinicb_aops = { readpage: udf_adinicb_readpage, writepage: udf_adinicb_writepage, + sync_page: block_sync_page, prepare_write: udf_adinicb_prepare_write, commit_write: udf_adinicb_commit_write, }; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index b0a9c42c0..3b8f6a4d4 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -125,7 +125,7 @@ void udf_discard_prealloc(struct inode * inode) udf_trunc(inode); } -static int udf_writepage(struct dentry *dentry, struct page *page) +static int udf_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page, udf_get_block); } @@ -148,6 +148,7 @@ static int udf_bmap(struct address_space *mapping, long block) struct address_space_operations udf_aops = { readpage: udf_readpage, writepage: udf_writepage, + sync_page: block_sync_page, prepare_write: udf_prepare_write, commit_write: generic_commit_write, bmap: udf_bmap, @@ -201,7 +202,7 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err) mark_buffer_dirty(bh, 1); udf_release_data(bh); - inode->i_data.a_ops->writepage(NULL, page); + inode->i_data.a_ops->writepage(NULL, NULL, page); UnlockPage(page); page_cache_release(page); diff --git a/fs/udf/namei.c b/fs/udf/namei.c index a44e19043..dcd980030 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -344,9 +344,6 @@ udf_add_entry(struct inode *dir, struct dentry *dentry, Uint32 extoffset, elen, offset; struct buffer_head *bh = NULL; - *err = -EINVAL; - if (!dir || !dir->i_nlink) - return NULL; sb = dir->i_sb; if (dentry->d_name.len) @@ -365,6 +362,7 @@ udf_add_entry(struct inode *dir, struct dentry *dentry, } else if (dir->i_size != 0) { + /* WTF??? */ *err = -ENOENT; return NULL; } @@ -724,7 +722,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode) cfi.fileCharacteristics = FILE_DIRECTORY | FILE_PARENT; udf_write_fi(&cfi, fi, &fibh, NULL, NULL); udf_release_data(fibh.sbh); - inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask); + inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; mark_inode_dirty(inode); @@ -1165,9 +1163,6 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry, if (new_inode) { - retval = -EBUSY; - if (!d_unhashed(new_dentry)) - goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_inode)) goto end_rename; diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 8c5c15d55..69f398d29 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -540,7 +540,7 @@ struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment, return NULL; } -static int ufs_writepage(struct dentry *dentry, struct page *page) +static int ufs_writepage(struct file *file, struct dentry *dentry, struct page *page) { return block_write_full_page(page,ufs_getfrag_block); } @@ -559,6 +559,7 @@ static int ufs_bmap(struct address_space *mapping, long block) struct address_space_operations ufs_aops = { readpage: ufs_readpage, writepage: ufs_writepage, + sync_page: block_sync_page, prepare_write: ufs_prepare_write, commit_write: generic_commit_write, bmap: ufs_bmap diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index a36a6c3af..c60fcbcdb 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -240,8 +240,6 @@ static struct buffer_head * ufs_add_entry (struct inode * dir, *err = -EINVAL; *res_dir = NULL; - if (!dir || !dir->i_nlink) - return NULL; sb = dir->i_sb; flags = sb->u.ufs_sb.s_flags; @@ -250,14 +248,6 @@ static struct buffer_head * ufs_add_entry (struct inode * dir, if (!namelen) return NULL; - /* - * Is this a busy deleted directory? Can't create new files if so - */ - if (dir->i_size == 0) - { - *err = -ENOENT; - return NULL; - } bh = ufs_bread (dir, 0, 0, err); if (!bh) return NULL; diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index 649ce16d4..2e172e80b 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -389,7 +389,7 @@ out_fail: extern kdev_t ROOT_DEV; static struct dentry *check_pseudo_root(struct super_block *sb) { - struct dentry *root, *init; + struct dentry *root, *sbin, *init; /* * Check whether we're mounted as the root device. @@ -398,34 +398,40 @@ static struct dentry *check_pseudo_root(struct super_block *sb) if (sb->s_dev != ROOT_DEV) goto out_noroot; - -printk("check_pseudo_root: mounted as root\n"); - root = lookup_dentry(UMSDOS_PSDROOT_NAME, dget(sb->s_root), 0); + /* + * lookup_dentry needs a (so far non-existent) root. + */ + printk(KERN_INFO "check_pseudo_root: mounted as root\n"); + root = lookup_one(UMSDOS_PSDROOT_NAME, sb->s_root); if (IS_ERR(root)) goto out_noroot; - if (!root->d_inode) + if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode)) goto out_dput; -printk("check_pseudo_root: found %s/%s\n", -root->d_parent->d_name.name, root->d_name.name); - /* look for /sbin/init */ - init = lookup_dentry("sbin/init", dget(root), 0); - if (!IS_ERR(init)) { - if (init->d_inode) - goto root_ok; - dput(init); - } - /* check for other files? */ - goto out_dput; + printk(KERN_INFO "check_pseudo_root: found %s/%s\n", root->d_parent->d_name.name, root->d_name.name); -root_ok: -printk("check_pseudo_root: found %s/%s, enabling pseudo-root\n", -init->d_parent->d_name.name, init->d_name.name); + /* look for /sbin/init */ + sbin = lookup_one("sbin", root); + if (IS_ERR(sbin)) + goto out_dput; + if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode)) + goto out_dput_sbin; + init = lookup_one("init", sbin); + if (IS_ERR(init)) + goto out_dput_sbin; + if (!init->d_inode) + goto out_dput_init; + printk(KERN_INFO "check_pseudo_root: found %s/%s, enabling pseudo-root\n", init->d_parent->d_name.name, init->d_name.name); + dput(sbin); dput(init); return root; /* Alternate root not found ... */ +out_dput_init: + dput(init); +out_dput_sbin: + dput(sbin); out_dput: dput(root); out_noroot: diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 1f7c788f5..ceb67870d 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -1080,9 +1080,6 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry) struct buffer_head *bh = NULL; struct msdos_dir_entry *de; - if (!d_unhashed(dentry)) - return -EBUSY; - res = fat_dir_empty(dentry->d_inode); if (res) return res; @@ -1202,9 +1199,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, } if (is_dir) { - res =-EBUSY; - if (!d_unhashed(new_dentry)) - goto rename_done; res = fat_dir_empty(new_inode); if (res) goto rename_done; |