summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
commitb9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch)
tree42d07b0c7246ae2536a702e7c5de9e2732341116 /fs
parent7406b0a326f2d70ade2671c37d1beef62249db97 (diff)
Merge with 2.3.99-pre6.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in2
-rw-r--r--fs/adfs/inode.c3
-rw-r--r--fs/affs/Changes6
-rw-r--r--fs/affs/bitmap.c29
-rw-r--r--fs/affs/file.c280
-rw-r--r--fs/affs/inode.c7
-rw-r--r--fs/autofs/autofs_i.h5
-rw-r--r--fs/autofs/dirhash.c24
-rw-r--r--fs/autofs/inode.c74
-rw-r--r--fs/autofs/root.c8
-rw-r--r--fs/autofs4/Makefile2
-rw-r--r--fs/autofs4/autofs_i.h21
-rw-r--r--fs/autofs4/expire.c15
-rw-r--r--fs/autofs4/init.c2
-rw-r--r--fs/autofs4/inode.c133
-rw-r--r--fs/autofs4/inohash.c68
-rw-r--r--fs/autofs4/root.c59
-rw-r--r--fs/autofs4/symlink.c2
-rw-r--r--fs/autofs4/waitq.c3
-rw-r--r--fs/bad_inode.c6
-rw-r--r--fs/bfs/file.c3
-rw-r--r--fs/binfmt_aout.c27
-rw-r--r--fs/binfmt_elf.c87
-rw-r--r--fs/block_dev.c4
-rw-r--r--fs/buffer.c13
-rw-r--r--fs/cramfs/inflate/adler32.c2
-rw-r--r--fs/cramfs/inflate/infblock.c36
-rw-r--r--fs/cramfs/inflate/infblock.h10
-rw-r--r--fs/cramfs/inflate/infcodes.c16
-rw-r--r--fs/cramfs/inflate/infcodes.h6
-rw-r--r--fs/cramfs/inflate/inffast.c14
-rw-r--r--fs/cramfs/inflate/inffast.h2
-rw-r--r--fs/cramfs/inflate/inflate.c34
-rw-r--r--fs/cramfs/inflate/inftrees.c8
-rw-r--r--fs/cramfs/inflate/inftrees.h6
-rw-r--r--fs/cramfs/inflate/infutil.c4
-rw-r--r--fs/cramfs/inflate/infutil.h8
-rw-r--r--fs/cramfs/inflate/uncompr.c8
-rw-r--r--fs/cramfs/inflate/zlib.h24
-rw-r--r--fs/cramfs/uncompress.c14
-rw-r--r--fs/dcache.c71
-rw-r--r--fs/devfs/base.c113
-rw-r--r--fs/efs/inode.c1
-rw-r--r--fs/exec.c32
-rw-r--r--fs/ext2/inode.c3
-rw-r--r--fs/ext2/namei.c11
-rw-r--r--fs/fat/file.c8
-rw-r--r--fs/fat/inode.c3
-rw-r--r--fs/hfs/inode.c3
-rw-r--r--fs/hpfs/file.c3
-rw-r--r--fs/hpfs/namei.c5
-rw-r--r--fs/inode.c68
-rw-r--r--fs/isofs/inode.c1
-rw-r--r--fs/locks.c87
-rw-r--r--fs/minix/inode.c3
-rw-r--r--fs/minix/namei.c7
-rw-r--r--fs/msdos/namei.c6
-rw-r--r--fs/namei.c317
-rw-r--r--fs/nfs/dir.c2
-rw-r--r--fs/nfs/file.c33
-rw-r--r--fs/nfs/flushd.c4
-rw-r--r--fs/nfs/inode.c28
-rw-r--r--fs/nfs/mount_clnt.c16
-rw-r--r--fs/nfs/nfsroot.c30
-rw-r--r--fs/nfs/read.c485
-rw-r--r--fs/nfs/write.c288
-rw-r--r--fs/nfsd/export.c79
-rw-r--r--fs/nfsd/nfs3xdr.c2
-rw-r--r--fs/nfsd/nfsproc.c2
-rw-r--r--fs/nfsd/vfs.c17
-rw-r--r--fs/ntfs/fs.c3
-rw-r--r--fs/open.c85
-rw-r--r--fs/partitions/Config.in3
-rw-r--r--fs/partitions/Makefile5
-rw-r--r--fs/partitions/acorn.c8
-rw-r--r--fs/partitions/check.c22
-rw-r--r--fs/partitions/ibm.c122
-rw-r--r--fs/partitions/ibm.h1
-rw-r--r--fs/partitions/msdos.c16
-rw-r--r--fs/pipe.c1
-rw-r--r--fs/proc/array.c10
-rw-r--r--fs/proc/base.c5
-rw-r--r--fs/proc/proc_misc.c38
-rw-r--r--fs/proc/proc_tty.c4
-rw-r--r--fs/qnx4/inode.c3
-rw-r--r--fs/qnx4/namei.c4
-rw-r--r--fs/ramfs/inode.c2
-rw-r--r--fs/readdir.c6
-rw-r--r--fs/romfs/inode.c3
-rw-r--r--fs/select.c4
-rw-r--r--fs/smbfs/file.c2
-rw-r--r--fs/stat.c8
-rw-r--r--fs/super.c689
-rw-r--r--fs/sysv/inode.c5
-rw-r--r--fs/sysv/namei.c7
-rw-r--r--fs/udf/file.c3
-rw-r--r--fs/udf/inode.c5
-rw-r--r--fs/udf/namei.c9
-rw-r--r--fs/ufs/inode.c3
-rw-r--r--fs/ufs/namei.c10
-rw-r--r--fs/umsdos/inode.c44
-rw-r--r--fs/vfat/namei.c6
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(&current->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
};
diff --git a/fs/exec.c b/fs/exec.c
index 22e151141..cec87c5aa 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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
diff --git a/fs/open.c b/fs/open.c
index 4a56314a7..771b6e040 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -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(&current->files->file_lock);
- FD_CLR(fd, current->files->open_fds);
- if (fd < current->files->next_fd)
- current->files->next_fd = fd;
- write_unlock(&current->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.
diff --git a/fs/pipe.c b/fs/pipe.c
index f25f5e514..d4583efc6 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -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;
diff --git a/fs/stat.c b/fs/stat.c
index af90ac70b..9a9987702 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -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;