summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
commit0ae8dceaebe3659ee0c3352c08125f403e77ebca (patch)
tree5085c389f09da78182b899d19fe1068b619a69dd /fs
parent273767781288c35c9d679e908672b9996cda4c34 (diff)
Merge with 2.3.10.
Diffstat (limited to 'fs')
-rw-r--r--fs/binfmt_aout.c3
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--fs/coda/cache.c2
-rw-r--r--fs/coda/cnode.c29
-rw-r--r--fs/coda/coda_linux.c2
-rw-r--r--fs/coda/dir.c8
-rw-r--r--fs/coda/inode.c36
-rw-r--r--fs/coda/sysctl.c50
-rw-r--r--fs/coda/upcall.c48
-rw-r--r--fs/devices.c2
-rw-r--r--fs/dquot.c21
-rw-r--r--fs/exec.c10
-rw-r--r--fs/ext2/ioctl.c38
-rw-r--r--fs/fat/dir.c12
-rw-r--r--fs/fat/mmap.c3
-rw-r--r--fs/fcntl.c52
-rw-r--r--fs/fifo.c1
-rw-r--r--fs/file_table.c132
-rw-r--r--fs/inode.c28
-rw-r--r--fs/ioctl.c6
-rw-r--r--fs/locks.c87
-rw-r--r--fs/minix/file.c2
-rw-r--r--fs/namei.c10
-rw-r--r--fs/ncpfs/dir.c1
-rw-r--r--fs/ncpfs/mmap.c3
-rw-r--r--fs/nfs/read.c5
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/nfsd/nfsctl.c1
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--fs/open.c74
-rw-r--r--fs/pipe.c6
-rw-r--r--fs/proc/fd.c7
-rw-r--r--fs/proc/inode.c24
-rw-r--r--fs/proc/link.c7
-rw-r--r--fs/proc/root.c48
-rw-r--r--fs/qnx4/dir.c5
-rw-r--r--fs/qnx4/symlinks.c4
-rw-r--r--fs/select.c12
-rw-r--r--fs/super.c1
-rw-r--r--fs/sysv/file.c3
-rw-r--r--fs/ufs/balloc.c22
-rw-r--r--fs/ufs/super.c3
-rw-r--r--fs/umsdos/file.c1
43 files changed, 499 insertions, 316 deletions
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 4723c6802..52c1f7aab 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -461,7 +461,8 @@ beyond_if:
return retval;
}
- current->mm->start_stack = create_aout_tables(bprm->p, bprm);
+ current->mm->start_stack =
+ (unsigned long) create_aout_tables((char *) bprm->p, bprm);
#ifdef __alpha__
regs->gp = ex.a_gpvalue;
#endif
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index bd3c8f490..e3087a18b 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -443,6 +443,8 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
retval = -ENOMEM;
size = elf_ex.e_phentsize * elf_ex.e_phnum;
+ if (size > 65536)
+ goto out;
elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
if (!elf_phdata)
goto out;
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 1c3b11199..d3412e52c 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -326,8 +326,8 @@ void coda_flag_inode_children(struct inode *inode, int flag)
while ( alias != &inode->i_dentry ) {
alias_de = list_entry(alias, struct dentry, d_alias);
coda_flag_children(alias_de, flag);
- shrink_dcache_parent(alias_de);
alias = alias->next;
+ shrink_dcache_parent(alias_de);
}
}
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index dd1e03f5f..ffae7746f 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -14,6 +14,17 @@
extern int coda_debug;
extern int coda_print_entry;
+inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
+{
+ if (fid1->Vnode != fid2->Vnode)
+ return 0;
+ if (fid1->Volume != fid2->Volume)
+ return 0;
+ if (fid1->Unique != fid2->Unique)
+ return 0;
+ return 1;
+}
+
/* cnode.c */
static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
{
@@ -71,8 +82,14 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
}
cnp = ITOC(*inode);
- if ( cnp->c_magic != 0 ) {
- printk("coda_cnode make on initialized inode %ld, old %s new
+ /* see if we've got it already */
+ if ( cnp->c_magic != 0 && coda_fideq(fid, &cnp->c_fid)) {
+ return 0;
+ }
+
+ /* not fresh: collision */
+ if ( cnp->c_magic != 0 ) {
+ printk("coda_cnode_make on initialized inode %ld, old %s new
%s!\n",
(*inode)->i_ino, coda_f2s(&cnp->c_fid), coda_f2s2(fid));
iput(*inode);
@@ -106,14 +123,6 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
return 0;
}
-inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
-{
- int eq;
- eq = ( (fid1->Vnode == fid2->Vnode) &&
- (fid1->Volume == fid2->Volume) &&
- (fid1->Unique == fid2->Unique) );
- return eq;
-}
void coda_replace_fid(struct inode *inode, struct ViceFid *oldfid,
struct ViceFid *newfid)
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index f684f3a78..5f2f3c467 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -215,6 +215,8 @@ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
if (attr->va_ctime.tv_sec != -1)
inode->i_ctime = attr->va_ctime.tv_sec;
}
+
+
/*
* BSD sets attributes that need not be modified to -1.
* Linux uses the valid field to indicate what should be
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 4313edb69..10b1cb171 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -800,6 +800,10 @@ static int coda_dentry_revalidate(struct dentry *de, int flags)
shrink_dcache_parent(de);
+ /* propagate for a flush */
+ if (cii->c_flags & C_FLUSH)
+ coda_flag_inode_children(inode, C_FLUSH);
+
if (de->d_count > 1) {
/* pretend it's valid, but don't change the flags */
CDEBUG(D_DOWNCALL, "BOOM for: ino %ld, %s\n",
@@ -807,10 +811,6 @@ static int coda_dentry_revalidate(struct dentry *de, int flags)
return 1;
}
- /* propagate for a flush */
- if (cii->c_flags & C_FLUSH)
- coda_flag_inode_children(inode, C_FLUSH);
-
/* clear the flags. */
cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 49359f260..604e906a2 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -22,8 +22,6 @@
#include <asm/uaccess.h>
#include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <asm/segment.h>
@@ -75,6 +73,9 @@ static struct super_block * coda_read_super(struct super_block *sb,
if ( sbi->sbi_sb ) {
printk("Already mounted\n");
+ unlock_super(sb);
+ EXIT;
+ MOD_DEC_USE_COUNT;
return NULL;
}
@@ -98,7 +99,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
printk("coda_read_super: coda_get_rootfid failed with %d\n",
error);
sb->s_dev = 0;
- unlock_super(sb);
goto error;
}
printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
@@ -108,7 +108,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
if ( error || !root ) {
printk("Failure of coda_cnode_make for root: error %d\n", error);
sb->s_dev = 0;
- unlock_super(sb);
goto error;
}
@@ -121,6 +120,7 @@ static struct super_block * coda_read_super(struct super_block *sb,
return sb;
error:
+ unlock_super(sb);
EXIT;
MOD_DEC_USE_COUNT;
if (sbi) {
@@ -145,7 +145,6 @@ static void coda_put_super(struct super_block *sb)
sb->s_dev = 0;
coda_cache_clear_all(sb);
sb_info = coda_sbp(sb);
-/* sb_info->sbi_vcomm->vc_inuse = 0; You can not do this: psdev_release would see usagecount == 0 and would refuse to decrease MOD_USE_COUNT --pavel */
coda_super_info.sbi_sb = NULL;
printk("Coda: Bye bye.\n");
memset(sb_info, 0, sizeof(* sb_info));
@@ -209,7 +208,7 @@ static void coda_delete_inode(struct inode *inode)
EXIT;
}
-static int coda_notify_change(struct dentry *de, struct iattr *iattr)
+static int coda_notify_change(struct dentry *de, struct iattr *iattr)
{
struct inode *inode = de->d_inode;
struct coda_inode_info *cii;
@@ -238,21 +237,32 @@ static int coda_notify_change(struct dentry *de, struct iattr *iattr)
return error;
}
-/* we need _something_ for this routine. Let's mimic AFS */
static int coda_statfs(struct super_block *sb, struct statfs *buf,
int bufsiz)
{
struct statfs tmp;
+ int error;
+
+ memset(&tmp, 0, sizeof(struct statfs));
+
+ error = venus_statfs(sb, &tmp);
+ if (error) {
+ /* fake something like AFS does */
+ tmp.f_blocks = 9000000;
+ tmp.f_bfree = 9000000;
+ tmp.f_bavail = 9000000;
+ tmp.f_files = 9000000;
+ tmp.f_ffree = 9000000;
+ }
+
+ /* and fill in the rest */
tmp.f_type = CODA_SUPER_MAGIC;
tmp.f_bsize = 1024;
- tmp.f_blocks = 9000000;
- tmp.f_bfree = 9000000;
- tmp.f_bavail = 9000000 ;
- tmp.f_files = 9000000;
- tmp.f_ffree = 9000000;
- tmp.f_namelen = 0;
+ tmp.f_namelen = CODA_MAXNAMLEN;
+
copy_to_user(buf, &tmp, bufsiz);
+
return 0;
}
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index 79a4c7ebb..e35174e5c 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -71,6 +71,7 @@ struct coda_permission_stats coda_permission_stat;
struct coda_cache_inv_stats coda_cache_inv_stat;
struct coda_upcall_stats_entry coda_upcall_stat[CODA_NCALLS];
struct coda_upcallstats coda_callstats;
+int coda_upcall_timestamping = 0;
/* keep this in sync with coda.h! */
char *coda_upcall_names[] = {
@@ -103,9 +104,12 @@ char *coda_upcall_names[] = {
"purgeuser ", /* 26 */
"zapfile ", /* 27 */
"zapdir ", /* 28 */
- "zapvnode ", /* 28 */
+ "noop2 ", /* 29 */
"purgefid ", /* 30 */
- "open_by_path" /* 31 */
+ "open_by_path", /* 31 */
+ "resolve ", /* 32 */
+ "reintegrate ", /* 33 */
+ "statfs " /* 34 */
};
@@ -133,8 +137,7 @@ void reset_coda_cache_inv_stats( void )
void do_time_stats( struct coda_upcall_stats_entry * pentry,
unsigned long runtime )
{
-
- unsigned long time = runtime * 1000 /HZ; /* time in ms */
+ unsigned long time = runtime; /* time in us */
CDEBUG(D_SPECIAL, "time: %ld\n", time);
if ( pentry->count == 0 ) {
@@ -221,9 +224,12 @@ int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
{
if ( write ) {
reset_coda_vfs_stats();
+
+ filp->f_pos += *lenp;
+ } else {
+ *lenp = 0;
}
-
- *lenp = 0;
+
return 0;
}
@@ -232,10 +238,19 @@ int do_reset_coda_upcall_stats( ctl_table * table, int write,
size_t * lenp )
{
if ( write ) {
+ if (*lenp > 0) {
+ char c;
+ if (get_user(c, (char *)buffer))
+ return -EFAULT;
+ coda_upcall_timestamping = (c == '1');
+ }
reset_coda_upcall_stats();
+
+ filp->f_pos += *lenp;
+ } else {
+ *lenp = 0;
}
-
- *lenp = 0;
+
return 0;
}
@@ -245,9 +260,12 @@ int do_reset_coda_permission_stats( ctl_table * table, int write,
{
if ( write ) {
reset_coda_permission_stats();
+
+ filp->f_pos += *lenp;
+ } else {
+ *lenp = 0;
}
-
- *lenp = 0;
+
return 0;
}
@@ -257,9 +275,12 @@ int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
{
if ( write ) {
reset_coda_cache_inv_stats();
+
+ filp->f_pos += *lenp;
+ } else {
+ *lenp = 0;
}
- *lenp = 0;
return 0;
}
@@ -347,12 +368,12 @@ int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
if ( offset < 160)
len += sprintf( buffer + len,"%-79s\n", "======================");
if ( offset < 240)
- len += sprintf( buffer + len,"%-79s\n", "upcall\t\t count\tavg time(ms)\tstd deviation(ms)");
+ len += sprintf( buffer + len,"%-79s\n", "upcall count avg time(us) std deviation(us)");
if ( offset < 320)
- len += sprintf( buffer + len,"%-79s\n", "------\t\t -----\t------------\t-----------------");
+ len += sprintf( buffer + len,"%-79s\n", "------ ----- ------------ -----------------");
pos = 320;
for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
- tmplen += sprintf(tmpbuf,"%s\t%9d\t%10ld\t%10ld",
+ tmplen += sprintf(tmpbuf,"%s %9d %10ld %10ld",
coda_upcall_names[i],
coda_upcall_stat[i].count,
get_time_average(&coda_upcall_stat[i]),
@@ -499,6 +520,7 @@ static void coda_proc_modcount(struct inode *inode, int fill)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
+
}
#endif
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index a0c1092b2..62fd62e35 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -580,6 +580,33 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
return error;
}
+int venus_statfs(struct super_block *sb, struct statfs *sfs)
+{
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+
+ insize = max(INSIZE(statfs), OUTSIZE(statfs));
+ UPARG(CODA_STATFS);
+
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+ if (!error) {
+ sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
+ sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
+ sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
+ sfs->f_files = outp->coda_statfs.stat.f_files;
+ sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
+ } else {
+ printk("coda_statfs: Venus returns: %d\n", error);
+ }
+
+ if (inp) CODA_FREE(inp, insize);
+ CDEBUG(D_INODE, " result %d\n",error);
+ EXIT;
+ return error;
+}
+
/*
* coda_upcall and coda_downcall routines.
*
@@ -588,10 +615,12 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
{
DECLARE_WAITQUEUE(wait, current);
- unsigned long posttime;
+ struct timeval begin = { 0, 0 }, end = { 0, 0 };
vmp->uc_posttime = jiffies;
- posttime = jiffies;
+
+ if (coda_upcall_timestamping)
+ do_gettimeofday(&begin);
add_wait_queue(&vmp->uc_sleep, &wait);
for (;;) {
@@ -620,9 +649,20 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
remove_wait_queue(&vmp->uc_sleep, &wait);
current->state = TASK_RUNNING;
- CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", posttime, jiffies-posttime);
- return (jiffies - posttime);
+ if (coda_upcall_timestamping && begin.tv_sec != 0) {
+ do_gettimeofday(&end);
+
+ if (end.tv_usec < begin.tv_usec) {
+ end.tv_usec += 1000000; end.tv_sec--;
+ }
+ end.tv_sec -= begin.tv_sec;
+ end.tv_usec -= begin.tv_usec;
+ }
+
+ CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
+ begin.tv_sec, begin.tv_usec, end.tv_sec, end.tv_usec);
+ return ((end.tv_sec * 1000000) + end.tv_usec);
}
diff --git a/fs/devices.c b/fs/devices.c
index 7bdadd5fb..a436f60de 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -277,6 +277,7 @@ struct inode_operations blkdev_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
@@ -333,6 +334,7 @@ struct inode_operations chrdev_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
diff --git a/fs/dquot.c b/fs/dquot.c
index dfef0a63a..9dfbac082 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -577,32 +577,35 @@ we_slept:
static void add_dquot_ref(kdev_t dev, short type)
{
struct super_block *sb = get_super(dev);
- struct file *filp;
+ struct list_head *p;
struct inode *inode;
if (!sb || !sb->dq_op)
return; /* nothing to do */
- for (filp = inuse_filps; filp; filp = filp->f_next) {
+ file_list_lock();
+ for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+ struct file *filp = list_entry(p, struct file, f_list);
if (!filp->f_dentry)
continue;
- if (filp->f_dentry->d_sb != sb)
- continue;
inode = filp->f_dentry->d_inode;
if (!inode)
continue;
/* N.B. race problem -- filp could become unused */
if (filp->f_mode & FMODE_WRITE) {
+ file_list_unlock();
sb->dq_op->initialize(inode, type);
inode->i_flags |= S_QUOTA;
+ file_list_lock();
}
}
+ file_list_unlock();
}
static void reset_dquot_ptrs(kdev_t dev, short type)
{
struct super_block *sb = get_super(dev);
- struct file *filp;
+ struct list_head *p;
struct inode *inode;
struct dquot *dquot;
int cnt;
@@ -614,11 +617,11 @@ restart:
/* free any quota for unused dentries */
shrink_dcache_sb(sb);
- for (filp = inuse_filps; filp; filp = filp->f_next) {
+ file_list_lock();
+ for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+ struct file *filp = list_entry(p, struct file, f_list);
if (!filp->f_dentry)
continue;
- if (filp->f_dentry->d_sb != sb)
- continue;
inode = filp->f_dentry->d_inode;
if (!inode)
continue;
@@ -637,12 +640,14 @@ restart:
inode->i_flags &= ~S_QUOTA;
put_it:
if (dquot != NODQUOT) {
+ file_list_unlock();
dqput(dquot);
/* we may have blocked ... */
goto restart;
}
}
}
+ file_list_unlock();
}
static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
diff --git a/fs/exec.c b/fs/exec.c
index 83b1834de..be92bb62c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -119,8 +119,12 @@ int open_dentry(struct dentry * dentry, int mode)
{
struct inode * inode = dentry->d_inode;
struct file * f;
+ struct list_head * l = NULL;
int fd, error;
+ if (inode->i_sb)
+ l = &inode->i_sb->s_files;
+
error = -EINVAL;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto out;
@@ -141,6 +145,7 @@ int open_dentry(struct dentry * dentry, int mode)
if (error)
goto out_filp;
}
+ file_move(f, l);
fd_install(fd, f);
dget(dentry);
}
@@ -465,8 +470,7 @@ static inline void flush_old_files(struct files_struct * files)
i = j * __NFDBITS;
if (i >= files->max_fds)
break;
- set = files->close_on_exec.fds_bits[j];
- files->close_on_exec.fds_bits[j] = 0;
+ set = xchg(&files->close_on_exec.fds_bits[j], 0);
j++;
for ( ; set ; i++,set >>= 1) {
if (set & 1)
@@ -559,7 +563,7 @@ int prepare_binprm(struct linux_binprm *bprm)
if ((retval = permission(inode, MAY_EXEC)) != 0)
return retval;
/* better not execute files which are being written to */
- if (inode->i_writecount > 0)
+ if (atomic_read(&inode->i_writecount) > 0)
return -ETXTBSY;
bprm->e_uid = current->euid;
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index ec21b0c4e..4d54fd354 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -27,28 +27,35 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
case EXT2_IOC_GETFLAGS:
flags = inode->u.ext2_i.i_flags & EXT2_FL_USER_VISIBLE;
return put_user(inode->u.ext2_i.i_flags, (int *) arg);
- case EXT2_IOC_SETFLAGS:
+ case EXT2_IOC_SETFLAGS: {
+ unsigned int oldflags;
+
+ if (IS_RDONLY(inode))
+ return -EROFS;
+
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ return -EPERM;
+
if (get_user(flags, (int *) arg))
return -EFAULT;
- flags = flags & EXT2_FL_USER_MODIFIABLE;
+
+ oldflags = inode->u.ext2_i.i_flags;
+
/*
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
- * the super user when the security level is zero.
+ * the relevant capability.
+ *
+ * This test looks nicer. Thanks to Pauline Middelink
*/
- if ((flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) ^
- (inode->u.ext2_i.i_flags &
- (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
- /* This test looks nicer. Thanks to Pauline Middelink */
+ if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) {
if (!capable(CAP_LINUX_IMMUTABLE))
return -EPERM;
- } else
- if ((current->fsuid != inode->i_uid) &&
- !capable(CAP_FOWNER))
- return -EPERM;
- if (IS_RDONLY(inode))
- return -EROFS;
- inode->u.ext2_i.i_flags = (inode->u.ext2_i.i_flags &
- ~EXT2_FL_USER_MODIFIABLE) | flags;
+ }
+
+ flags = flags & EXT2_FL_USER_MODIFIABLE;
+ flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE;
+ inode->u.ext2_i.i_flags = flags;
+
if (flags & EXT2_SYNC_FL)
inode->i_flags |= MS_SYNCHRONOUS;
else
@@ -68,6 +75,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
return 0;
+ }
case EXT2_IOC_GETVERSION:
return put_user(inode->i_generation, (int *) arg);
case EXT2_IOC_SETVERSION:
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 594baa0e2..82d29a0df 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -295,6 +295,8 @@ static int fat_readdirx(
char bufname[14];
char *ptname = bufname;
int dotoffset = 0;
+ unsigned long *furrfu = &lpos;
+ unsigned long dummy;
cpos = filp->f_pos;
/* Fake . and .. for the root directory. */
@@ -305,8 +307,11 @@ static int fat_readdirx(
cpos++;
filp->f_pos++;
}
- if (cpos == 2)
+ if (cpos == 2) {
+ dummy = 2;
+ furrfu = &dummy;
cpos = 0;
+ }
}
if (cpos & (sizeof(struct msdos_dir_entry)-1))
return -ENOENT;
@@ -440,7 +445,7 @@ ParseLong:
if (!long_slots||shortnames) {
if (both)
bufname[i] = '\0';
- if (filldir(dirent, bufname, i, lpos, inum) < 0)
+ if (filldir(dirent, bufname, i, *furrfu, inum) < 0)
goto FillFailed;
} else {
char longname[275];
@@ -451,11 +456,12 @@ ParseLong:
memcpy(&longname[long_len+1], bufname, i);
long_len += i;
}
- if (filldir(dirent, longname, long_len, lpos, inum) < 0)
+ if (filldir(dirent, longname, long_len, *furrfu, inum) < 0)
goto FillFailed;
}
RecEnd:
+ furrfu = &lpos;
filp->f_pos = cpos;
goto GetNew;
EODir:
diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c
index 0494ad013..80ec56b54 100644
--- a/fs/fat/mmap.c
+++ b/fs/fat/mmap.c
@@ -87,8 +87,7 @@ struct vm_operations_struct fat_file_mmap = {
NULL, /* advise */
fat_file_mmap_nopage, /* nopage */
NULL, /* wppage */
- NULL, /* swapout */
- NULL, /* swapin */
+ NULL /* swapout */
};
/*
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 666d88881..d12e66244 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -12,27 +12,19 @@
extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
-static inline int dupfd(unsigned int fd, unsigned int arg)
+static inline int dupfd(struct file *file, unsigned int arg)
{
struct files_struct * files = current->files;
- struct file * file;
int error;
- error = -EINVAL;
- if (arg >= NR_OPEN)
- goto out;
-
- error = -EBADF;
- file = fget(fd);
- if (!file)
- goto out;
-
error = -EMFILE;
+ write_lock(&files->file_lock);
arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
goto out_putf;
FD_SET(arg, &files->open_fds);
FD_CLR(arg, &files->close_on_exec);
+ write_unlock(&files->file_lock);
fd_install(arg, file);
error = arg;
out:
@@ -46,31 +38,35 @@ out_putf:
asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
int err = -EBADF;
+ struct file * file;
- lock_kernel();
- if (!fcheck(oldfd))
- goto out;
+ read_lock(&current->files->file_lock);
+ if (!(file = fcheck(oldfd)))
+ goto out_unlock;
err = newfd;
if (newfd == oldfd)
- goto out;
+ goto out_unlock;
err = -EBADF;
if (newfd >= NR_OPEN)
- goto out; /* following POSIX.1 6.2.1 */
+ goto out_unlock; /* following POSIX.1 6.2.1 */
+ get_file(file);
+ read_unlock(&current->files->file_lock);
sys_close(newfd);
- err = dupfd(oldfd, newfd);
+ err = dupfd(file, newfd);
out:
- unlock_kernel();
return err;
+out_unlock:
+ read_unlock(&current->files->file_lock);
+ goto out;
}
asmlinkage int sys_dup(unsigned int fildes)
{
- int ret;
-
- lock_kernel();
- ret = dupfd(fildes, 0);
- unlock_kernel();
+ int ret = -EBADF;
+ struct file * file = fget(fildes);
+ if (file)
+ ret = dupfd(file, 0);
return ret;
}
@@ -107,14 +103,18 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
struct file * filp;
long err = -EBADF;
- lock_kernel();
filp = fget(fd);
if (!filp)
goto out;
err = 0;
+ lock_kernel();
switch (cmd) {
case F_DUPFD:
- err = dupfd(fd, arg);
+ err = -EINVAL;
+ if (arg < NR_OPEN) {
+ get_file(filp);
+ err = dupfd(filp, arg);
+ }
break;
case F_GETFD:
err = FD_ISSET(fd, &current->files->close_on_exec);
@@ -178,8 +178,8 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
break;
}
fput(filp);
-out:
unlock_kernel();
+out:
return err;
}
diff --git a/fs/fifo.c b/fs/fifo.c
index 4566f97f4..3e641a6fe 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -179,6 +179,7 @@ struct inode_operations fifo_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
diff --git a/fs/file_table.c b/fs/file_table.c
index 80c3a08ba..cb9ef16e9 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
/* SLAB cache for filp's. */
static kmem_cache_t *filp_cache;
@@ -18,37 +19,12 @@ int nr_files = 0; /* read only */
int nr_free_files = 0; /* read only */
int max_files = NR_FILE;/* tunable */
-/* Free list management, if you are here you must have f_count == 0 */
-static struct file * free_filps = NULL;
-
-static void insert_file_free(struct file *file)
-{
- if((file->f_next = free_filps) != NULL)
- free_filps->f_pprev = &file->f_next;
- free_filps = file;
- file->f_pprev = &free_filps;
- nr_free_files++;
-}
-
-/* The list of in-use filp's must be exported (ugh...) */
-struct file *inuse_filps = NULL;
-
-static inline void put_inuse(struct file *file)
-{
- if((file->f_next = inuse_filps) != NULL)
- inuse_filps->f_pprev = &file->f_next;
- inuse_filps = file;
- file->f_pprev = &inuse_filps;
-}
-
-/* It does not matter which list it is on. */
-static inline void remove_filp(struct file *file)
-{
- if(file->f_next)
- file->f_next->f_pprev = file->f_pprev;
- *file->f_pprev = file->f_next;
-}
-
+/* Here the new files go */
+static LIST_HEAD(anon_list);
+/* And here the free ones sit */
+static LIST_HEAD(free_list);
+/* public *and* exported. Not pretty! */
+spinlock_t files_lock = SPIN_LOCK_UNLOCKED;
void __init file_table_init(void)
{
@@ -67,24 +43,30 @@ void __init file_table_init(void)
/* Find an unused file structure and return a pointer to it.
* Returns NULL, if there are no more free file structures or
* we run out of memory.
+ *
+ * SMP-safe.
*/
struct file * get_empty_filp(void)
{
static int old_max = 0;
struct file * f;
+ file_list_lock();
if (nr_free_files > NR_RESERVED_FILES) {
used_one:
- f = free_filps;
- remove_filp(f);
+ f = list_entry(free_list.next, struct file, f_list);
+ list_del(&f->f_list);
nr_free_files--;
new_one:
+ file_list_unlock();
memset(f, 0, sizeof(*f));
- atomic_set(&f->f_count, 1);
+ atomic_set(&f->f_count,1);
f->f_version = ++event;
f->f_uid = current->fsuid;
f->f_gid = current->fsgid;
- put_inuse(f);
+ file_list_lock();
+ list_add(&f->f_list, &anon_list);
+ file_list_unlock();
return f;
}
/*
@@ -96,7 +78,9 @@ struct file * get_empty_filp(void)
* Allocate a new one if we're below the limit.
*/
if (nr_files < max_files) {
+ file_list_unlock();
f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
+ file_list_lock();
if (f) {
nr_files++;
goto new_one;
@@ -108,6 +92,7 @@ struct file * get_empty_filp(void)
printk("VFS: file-max limit %d reached\n", max_files);
old_max = max_files;
}
+ file_list_unlock();
return NULL;
}
@@ -131,20 +116,77 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
return 0;
}
-void fput(struct file *file)
+void _fput(struct file *file)
{
- if (atomic_dec_and_test(&file->f_count)) {
- locks_remove_flock(file);
- __fput(file);
- remove_filp(file);
- insert_file_free(file);
- }
+ atomic_inc(&file->f_count);
+
+ lock_kernel();
+ locks_remove_flock(file); /* Still need the */
+ __fput(file); /* big lock here. */
+ unlock_kernel();
+
+ atomic_set(&file->f_count, 0);
+ file_list_lock();
+ list_del(&file->f_list);
+ list_add(&file->f_list, &free_list);
+ nr_free_files++;
+ file_list_unlock();
}
+/* Here. put_filp() is SMP-safe now. */
+
void put_filp(struct file *file)
{
- if (atomic_dec_and_test(&file->f_count)) {
- remove_filp(file);
- insert_file_free(file);
+ if(atomic_dec_and_test(&file->f_count)) {
+ file_list_lock();
+ list_del(&file->f_list);
+ list_add(&file->f_list, &free_list);
+ nr_free_files++;
+ file_list_unlock();
+ }
+}
+
+void file_move(struct file *file, struct list_head *list)
+{
+ if (!list)
+ return;
+ file_list_lock();
+ list_del(&file->f_list);
+ list_add(&file->f_list, list);
+ file_list_unlock();
+}
+
+void file_moveto(struct file *new, struct file *old)
+{
+ file_list_lock();
+ list_del(&new->f_list);
+ list_add(&new->f_list, &old->f_list);
+ file_list_unlock();
+}
+
+int fs_may_remount_ro(struct super_block *sb)
+{
+ struct list_head *p;
+
+ /* Check that no files are currently opened for writing. */
+ file_list_lock();
+ for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+ struct file *file = list_entry(p, struct file, f_list);
+ struct inode *inode = file->f_dentry->d_inode;
+ if (!inode)
+ continue;
+
+ /* File with pending delete? */
+ if (inode->i_nlink == 0)
+ goto too_bad;
+
+ /* Writable file? */
+ if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
+ return 0;
}
+ file_list_unlock();
+ return 1; /* Tis' cool bro. */
+too_bad:
+ file_list_unlock();
+ return 0;
}
diff --git a/fs/inode.c b/fs/inode.c
index 01fc64d23..242696d87 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -130,6 +130,7 @@ static inline void init_once(struct inode * inode)
INIT_LIST_HEAD(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_dentry);
sema_init(&inode->i_sem, 1);
+ spin_lock_init(&inode->i_shared_lock);
}
static inline void write_inode(struct inode *inode)
@@ -523,7 +524,7 @@ void clean_inode(struct inode *inode)
inode->i_sock = 0;
inode->i_op = NULL;
inode->i_nlink = 1;
- inode->i_writecount = 0;
+ atomic_set(&inode->i_writecount, 0);
inode->i_size = 0;
inode->i_generation = 0;
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
@@ -818,31 +819,6 @@ void __init inode_init(void)
max_inodes = max;
}
-/* This belongs in file_table.c, not here... */
-int fs_may_remount_ro(struct super_block *sb)
-{
- struct file *file;
-
- /* Check that no files are currently opened for writing. */
- for (file = inuse_filps; file; file = file->f_next) {
- struct inode *inode;
- if (!file->f_dentry)
- continue;
- inode = file->f_dentry->d_inode;
- if (!inode || inode->i_sb != sb)
- continue;
-
- /* File with pending delete? */
- if (inode->i_nlink == 0)
- return 0;
-
- /* Writable file? */
- if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
- return 0;
- }
- return 1; /* Tis' cool bro. */
-}
-
void update_atime (struct inode *inode)
{
if ( IS_NOATIME (inode) ) return;
diff --git a/fs/ioctl.c b/fs/ioctl.c
index e9f8e09b6..b9f2363e6 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -25,6 +25,8 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
return -EBADF;
if (inode->i_op->get_block == NULL)
return -EINVAL;
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
if ((error = get_user(block, (int *) arg)) != 0)
return error;
@@ -52,11 +54,11 @@ asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
unsigned int flag;
int on, error = -EBADF;
- lock_kernel();
filp = fget(fd);
if (!filp)
goto out;
error = 0;
+ lock_kernel();
switch (cmd) {
case FIOCLEX:
FD_SET(fd, &current->files->close_on_exec);
@@ -107,8 +109,8 @@ asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
}
fput(filp);
+ unlock_kernel();
out:
- unlock_kernel();
return error;
}
diff --git a/fs/locks.c b/fs/locks.c
index 728985c34..5cb324374 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -341,7 +341,11 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
error = filp->f_op->lock(filp, F_GETLK, &file_lock);
if (error < 0)
goto out_putf;
- fl = &file_lock;
+ else if (error == LOCK_USE_CLNT)
+ /* Bypass for NFS with no locking - 2.0.36 compat */
+ fl = posix_test_lock(filp, &file_lock);
+ else
+ fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else {
fl = posix_test_lock(filp, &file_lock);
}
@@ -402,14 +406,17 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
* and shared.
*/
if (IS_MANDLOCK(inode) &&
- (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
- inode->i_mmap) {
- struct vm_area_struct *vma = inode->i_mmap;
- error = -EAGAIN;
- do {
- if (vma->vm_flags & VM_MAYSHARE)
- goto out_putf;
- } while ((vma = vma->vm_next_share) != NULL);
+ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+ struct vm_area_struct *vma;
+ spin_lock(&inode->i_shared_lock);
+ for(vma = inode->i_mmap;vma;vma = vma->vm_next_share) {
+ if (!(vma->vm_flags & VM_MAYSHARE))
+ continue;
+ spin_unlock(&inode->i_shared_lock);
+ error = -EAGAIN;
+ goto out_putf;
+ }
+ spin_unlock(&inode->i_shared_lock);
}
error = -EINVAL;
@@ -546,47 +553,23 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
return (cfl);
}
-int locks_verify_locked(struct inode *inode)
-{
- /* Candidates for mandatory locking have the setgid bit set
- * but no group execute bit - an otherwise meaningless combination.
- */
- if (IS_MANDLOCK(inode) &&
- (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
- return (locks_mandatory_locked(inode));
- return (0);
-}
-
-int locks_verify_area(int read_write, struct inode *inode, struct file *filp,
- loff_t offset, size_t count)
-{
- /* Candidates for mandatory locking have the setgid bit set
- * but no group execute bit - an otherwise meaningless combination.
- */
- if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
- int retval;
- lock_kernel();
- retval = locks_mandatory_area(read_write, inode, filp, offset, count);
- unlock_kernel();
- return retval;
- }
- return 0;
-}
-
int locks_mandatory_locked(struct inode *inode)
{
fl_owner_t owner = current->files;
struct file_lock *fl;
- /* Search the lock list for this inode for any POSIX locks.
+ /*
+ * Search the lock list for this inode for any POSIX locks.
*/
+ lock_kernel();
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
if (fl->fl_owner != owner)
- return (-EAGAIN);
+ break;
}
- return (0);
+ unlock_kernel();
+ return fl ? -EAGAIN : 0;
}
int locks_mandatory_area(int read_write, struct inode *inode,
@@ -595,6 +578,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
{
struct file_lock *fl;
struct file_lock tfl;
+ int error;
memset(&tfl, 0, sizeof(tfl));
@@ -607,31 +591,39 @@ int locks_mandatory_area(int read_write, struct inode *inode,
tfl.fl_start = offset;
tfl.fl_end = offset + count - 1;
+ error = 0;
+ lock_kernel();
+
repeat:
/* Search the lock list for this inode for locks that conflict with
* the proposed read/write.
*/
- for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+ for (fl = inode->i_flock; ; fl = fl->fl_next) {
+ error = 0;
+ if (!fl)
+ break;
if (!(fl->fl_flags & FL_POSIX))
continue;
/* Block for writes against a "read" lock,
* and both reads and writes against a "write" lock.
*/
if (posix_locks_conflict(fl, &tfl)) {
+ error = -EAGAIN;
if (filp && (filp->f_flags & O_NONBLOCK))
- return (-EAGAIN);
+ break;
+ error = -ERESTARTSYS;
if (signal_pending(current))
- return (-ERESTARTSYS);
+ break;
+ error = -EDEADLK;
if (posix_locks_deadlock(&tfl, fl))
- return (-EDEADLK);
+ break;
locks_insert_block(fl, &tfl);
interruptible_sleep_on(&tfl.fl_wait);
locks_delete_block(fl, &tfl);
- if (signal_pending(current))
- return (-ERESTARTSYS);
- /* If we've been sleeping someone might have
+ /*
+ * If we've been sleeping someone might have
* changed the permissions behind our back.
*/
if ((inode->i_mode & (S_ISGID | S_IXGRP)) != S_ISGID)
@@ -639,7 +631,8 @@ repeat:
goto repeat;
}
}
- return (0);
+ unlock_kernel();
+ return error;
}
/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 14d478bde..9eab1fb17 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -7,7 +7,6 @@
*/
#include <linux/sched.h>
-#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
@@ -25,7 +24,6 @@
#define MAX(a,b) (((a)>(b))?(a):(b))
#include <linux/fs.h>
-#include <linux/minix_fs.h>
/*
* Write to a file (through the page cache).
diff --git a/fs/namei.c b/fs/namei.c
index 9769ce1bb..e39cd24e1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -171,18 +171,22 @@ int permission(struct inode * inode,int mask)
* 0: no writers, no VM_DENYWRITE mappings
* < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
* > 0: (i_writecount) users are writing to the file.
+ *
+ * WARNING: as soon as we will move get_write_access(), do_mmap() or
+ * prepare_binfmt() out of the big lock we will need a spinlock protecting
+ * the checks in all 3. For the time being it is not needed.
*/
int get_write_access(struct inode * inode)
{
- if (inode->i_writecount < 0)
+ if (atomic_read(&inode->i_writecount) < 0)
return -ETXTBSY;
- inode->i_writecount++;
+ atomic_inc(&inode->i_writecount);
return 0;
}
void put_write_access(struct inode * inode)
{
- inode->i_writecount--;
+ atomic_dec(&inode->i_writecount);
}
/*
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 1f92a89fb..cf4c13fde 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -19,7 +19,6 @@
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
-#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/ncp_fs.h>
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index c9254f4f6..776e9366b 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -98,8 +98,7 @@ struct vm_operations_struct ncp_file_mmap =
NULL, /* advise */
ncp_file_mmap_nopage, /* nopage */
NULL, /* wppage */
- NULL, /* swapout */
- NULL, /* swapin */
+ NULL /* swapout */
};
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 843f6b23e..899b62c82 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -90,8 +90,9 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
/* Set up arguments and perform rpc call */
nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize);
- result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ,
- &rqst.ra_args, &rqst.ra_res, flags);
+ lock_kernel();
+ result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ, &rqst.ra_args, &rqst.ra_res, flags);
+ unlock_kernel();
/*
* Even if we had a partial success we can't mark the page
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 8b63cbf66..77c1db091 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -305,6 +305,7 @@ create_write_request(struct file * file, struct page *page, unsigned int offset,
goto out_req;
/* Put the task on inode's writeback request list. */
+ get_file(file);
wreq->wb_file = file;
wreq->wb_pid = current->pid;
wreq->wb_page = page;
@@ -467,7 +468,6 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
* The IO completion will then free the page and the dentry.
*/
get_page(page);
- atomic_inc(&file->f_count);
/* Schedule request */
synchronous = schedule_write_request(req, synchronous);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index fd7a5b227..150acc6d9 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -18,7 +18,6 @@
#include <linux/fcntl.h>
#include <linux/net.h>
#include <linux/in.h>
-#include <linux/version.h>
#include <linux/unistd.h>
#include <linux/malloc.h>
#include <linux/proc_fs.h>
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 63294ae29..14cb7d50f 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -585,7 +585,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
* nice and simple solution (IMHO), and it seems to
* work:-)
*/
- if (EX_WGATHER(exp) && (inode->i_writecount > 1
+ if (EX_WGATHER(exp) && (atomic_read(&inode->i_writecount) > 1
|| (last_ino == inode->i_ino && last_dev == inode->i_dev))) {
#if 0
interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000);
diff --git a/fs/open.c b/fs/open.c
index deb898f76..c0f806f69 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -37,29 +37,21 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf)
asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
{
struct file * file;
- struct inode * inode;
- struct dentry * dentry;
struct super_block * sb;
int error;
- lock_kernel();
error = -EBADF;
file = fget(fd);
if (!file)
goto out;
- error = -ENOENT;
- if (!(dentry = file->f_dentry))
- goto out_putf;
- if (!(inode = dentry->d_inode))
- goto out_putf;
error = -ENODEV;
- sb = inode->i_sb;
+ sb = file->f_dentry->d_inode->i_sb;
+ lock_kernel();
if (sb && sb->s_op && sb->s_op->statfs)
error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
-out_putf:
+ unlock_kernel();
fput(file);
out:
- unlock_kernel();
return error;
}
@@ -143,7 +135,6 @@ asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
struct file * file;
int error;
- lock_kernel();
error = -EBADF;
file = fget(fd);
if (!file)
@@ -162,12 +153,13 @@ asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
length<inode->i_size ? length : inode->i_size,
abs(inode->i_size - length));
+ lock_kernel();
if (!error)
error = do_truncate(dentry, length);
+ unlock_kernel();
out_putf:
fput(file);
out:
- unlock_kernel();
return error;
}
@@ -361,8 +353,6 @@ asmlinkage int sys_fchdir(unsigned int fd)
struct inode *inode;
int error;
- lock_kernel();
-
error = -EBADF;
file = fget(fd);
if (!file)
@@ -378,16 +368,17 @@ asmlinkage int sys_fchdir(unsigned int fd)
if (!S_ISDIR(inode->i_mode))
goto out_putf;
+ lock_kernel();
error = permission(inode, MAY_EXEC);
if (!error) {
struct dentry *tmp = current->fs->pwd;
current->fs->pwd = dget(dentry);
dput(tmp);
}
+ unlock_kernel();
out_putf:
fput(file);
out:
- unlock_kernel();
return error;
}
@@ -439,7 +430,6 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
int err = -EBADF;
struct iattr newattrs;
- lock_kernel();
file = fget(fd);
if (!file)
goto out;
@@ -460,12 +450,13 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+ lock_kernel();
err = notify_change(dentry, &newattrs);
+ unlock_kernel();
out_putf:
fput(file);
out:
- unlock_kernel();
return err;
}
@@ -601,17 +592,17 @@ asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
struct file * file;
int error = -EBADF;
- lock_kernel();
file = fget(fd);
if (!file)
goto out;
error = -ENOENT;
+ lock_kernel();
if ((dentry = file->f_dentry) != NULL)
error = chown_common(dentry, user, group);
+ unlock_kernel();
fput(file);
out:
- unlock_kernel();
return error;
}
@@ -663,6 +654,8 @@ struct file *filp_open(const char * filename, int flags, int mode)
f->f_op = NULL;
if (inode->i_op)
f->f_op = inode->i_op->default_file_ops;
+ if (inode->i_sb)
+ file_move(f, &inode->i_sb->s_files);
if (f->f_op && f->f_op->open) {
error = f->f_op->open(inode,f);
if (error)
@@ -693,6 +686,8 @@ int get_unused_fd(void)
int fd, error;
error = -EMFILE;
+
+ write_lock(&files->file_lock);
fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
/*
* N.B. For clone tasks sharing a files structure, this test
@@ -715,12 +710,15 @@ int get_unused_fd(void)
error = fd;
out:
+ write_unlock(&files->file_lock);
return error;
}
inline void put_unused_fd(unsigned int fd)
{
+ write_lock(&current->files->file_lock);
FD_CLR(fd, &current->files->open_fds);
+ write_unlock(&current->files->file_lock);
}
asmlinkage int sys_open(const char * filename, int flags, int mode)
@@ -731,17 +729,18 @@ asmlinkage int sys_open(const char * filename, int flags, int mode)
tmp = getname(filename);
fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
- lock_kernel();
fd = get_unused_fd();
if (fd >= 0) {
- struct file * f = filp_open(tmp, flags, mode);
+ struct file * f;
+ lock_kernel();
+ f = filp_open(tmp, flags, mode);
+ unlock_kernel();
error = PTR_ERR(f);
if (IS_ERR(f))
goto out_error;
fd_install(fd, f);
}
out:
- unlock_kernel();
putname(tmp);
}
return fd;
@@ -790,7 +789,7 @@ int filp_close(struct file *filp, fl_owner_t id)
int retval;
struct dentry *dentry = filp->f_dentry;
- if (!atomic_read(&filp->f_count)) {
+ if (!file_count(filp)) {
printk("VFS: Close: file count is 0\n");
return 0;
}
@@ -812,19 +811,24 @@ asmlinkage int sys_close(unsigned int fd)
{
int error;
struct file * filp;
+ struct files_struct * files = current->files;
- lock_kernel();
error = -EBADF;
- filp = fcheck(fd);
- if (filp) {
- struct files_struct * files = current->files;
- files->fd[fd] = NULL;
- put_unused_fd(fd);
- FD_CLR(fd, &files->close_on_exec);
- error = filp_close(filp, files);
- }
+ write_lock(&files->file_lock);
+ filp = frip(fd);
+ if (!filp)
+ goto out_unlock;
+ FD_CLR(fd, &files->close_on_exec);
+ write_unlock(&files->file_lock);
+ put_unused_fd(fd);
+ lock_kernel();
+ error = filp_close(filp, files);
unlock_kernel();
+out:
return error;
+out_unlock:
+ write_unlock(&files->file_lock);
+ goto out;
}
/*
@@ -835,14 +839,14 @@ asmlinkage int sys_vhangup(void)
{
int ret = -EPERM;
- lock_kernel();
if (!capable(CAP_SYS_TTY_CONFIG))
goto out;
/* If there is a controlling tty, hang it up */
+ lock_kernel();
if (current->tty)
tty_vhangup(current->tty);
+ unlock_kernel();
ret = 0;
out:
- unlock_kernel();
return ret;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index 71f20bec5..2303ca328 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -27,7 +27,7 @@
/* Florian Coosmann (FGC) ^ current = 1 */
/* Additionally, we now use locking technique. This prevents race condition */
/* in case of paging and multiple read/write on the same pipe. (FGC) */
-
+/* Reads with count = 0 should always return 0. Julian Bradfield 1999-06-07. */
static ssize_t do_pipe_read(struct file * filp, char * buf, size_t count)
{
@@ -144,9 +144,12 @@ static ssize_t pipe_read(struct file * filp, char * buf, size_t count, loff_t *p
{
ssize_t retval;
+
if (ppos != &filp->f_pos)
return -ESPIPE;
+ if ( !count ) return 0;
+
lock_kernel();
retval = do_pipe_read(filp, buf, count);
unlock_kernel();
@@ -480,6 +483,7 @@ struct inode_operations pipe_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index a900d01bf..195ca41b8 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -104,7 +104,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
read_lock(&tasklist_lock);
file = NULL;
p = find_task_by_pid(pid);
- if (p)
+ if (p && p->files)
file = fcheck_task(p, fd);
read_unlock(&tasklist_lock);
@@ -114,7 +114,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
* is NULL
*/
- if (!file || !file->f_dentry)
+ if (!file)
goto out;
ino = (pid << 16) + PROC_PID_FD_DIR + fd;
@@ -161,10 +161,9 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
for (fd -= 2 ; p->files && fd < p->files->max_fds; fd++, filp->f_pos++)
{
- struct file * file = fcheck_task(p, fd);
unsigned int i,j;
- if (!file || !file->f_dentry)
+ if (!fcheck_task(p, fd))
continue;
j = NUMBUF;
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 970e63a96..a5596e4ee 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -87,13 +87,26 @@ static void proc_delete_inode(struct inode *inode)
}
}
+struct super_block *proc_super_blocks = NULL;
+
+static void proc_put_super(struct super_block *sb)
+{
+ struct super_block **p = &proc_super_blocks;
+ while (*p != sb) {
+ if (!*p) /* should never happen */
+ return;
+ p = (struct super_block **)&(*p)->u.generic_sbp;
+ }
+ *p = (struct super_block *)(*p)->u.generic_sbp;
+}
+
static struct super_operations proc_sops = {
proc_read_inode,
proc_write_inode,
proc_put_inode,
proc_delete_inode, /* delete_inode(struct inode *) */
NULL,
- NULL,
+ proc_put_super,
NULL,
proc_statfs,
NULL
@@ -323,6 +336,8 @@ struct super_block *proc_read_super(struct super_block *s,void *data,
if (!s->s_root)
goto out_no_root;
parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
+ s->u.generic_sbp = (void*) proc_super_blocks;
+ proc_super_blocks = s;
unlock_super(s);
return s;
@@ -385,9 +400,12 @@ void proc_read_inode(struct inode * inode)
if (ino & PROC_PID_FD_DIR) {
struct file * file;
ino &= 0x7fff;
+ if (!p->files) /* can we ever get here if that's the case? */
+ goto out_unlock;
+ read_lock(&p->files->file_lock);
file = fcheck_task(p, ino);
if (!file)
- goto out_unlock;
+ goto out_unlock2;
inode->i_op = &proc_link_inode_operations;
inode->i_size = 64;
@@ -396,6 +414,8 @@ void proc_read_inode(struct inode * inode)
inode->i_mode |= S_IRUSR | S_IXUSR;
if (file->f_mode & 2)
inode->i_mode |= S_IWUSR | S_IXUSR;
+out_unlock2:
+ read_unlock(&p->files->file_lock);
}
out_unlock:
/* Defer unlocking until we're done with the task */
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 647dc339f..6f5c63ec3 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -119,10 +119,14 @@ static struct dentry * proc_follow_link(struct dentry *dentry,
if (ino & PROC_PID_FD_DIR) {
struct file * file;
ino &= 0x7fff;
+ if (!p->files) /* shouldn't happen here */
+ goto out_unlock;
+ read_lock(&p->files->file_lock);
file = fcheck_task(p, ino);
if (!file || !file->f_dentry)
goto out_unlock;
result = file->f_dentry;
+ read_unlock(&p->files->file_lock);
goto out_dget;
}
}
@@ -146,6 +150,9 @@ static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
int len;
+ if(tmp==NULL)
+ return -ENOMEM;
+
/* Check for special dentries.. */
pattern = NULL;
inode = dentry->d_inode;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index d08860c26..df3c0b049 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -365,24 +365,36 @@ int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
*/
static void proc_kill_inodes(int ino)
{
- struct file *filp;
-
- /* inuse_filps is protected by the single kernel lock */
- for (filp = inuse_filps; filp; filp = filp->f_next) {
- struct dentry * dentry;
- struct inode * inode;
-
- dentry = filp->f_dentry;
- if (!dentry)
- continue;
- if (dentry->d_op != &proc_dentry_operations)
- continue;
- inode = dentry->d_inode;
- if (!inode)
- continue;
- if (inode->i_ino != ino)
- continue;
- filp->f_op = NULL;
+ struct list_head *p;
+ struct super_block *sb;
+
+ /*
+ * Actually it's a partial revoke(). We have to go through all
+ * copies of procfs. proc_super_blocks is protected by the big
+ * lock for the time being.
+ */
+ for (sb = proc_super_blocks;
+ sb;
+ sb = (struct super_block*)sb->u.generic_sbp) {
+ file_list_lock();
+ for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+ struct file * filp = list_entry(p, struct file, f_list);
+ struct dentry * dentry;
+ struct inode * inode;
+
+ dentry = filp->f_dentry;
+ if (!dentry)
+ continue;
+ if (dentry->d_op != &proc_dentry_operations)
+ continue;
+ inode = dentry->d_inode;
+ if (!inode)
+ continue;
+ if (inode->i_ino != ino)
+ continue;
+ filp->f_op = NULL;
+ }
+ file_list_unlock();
}
}
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 8b27142a3..0fbae7262 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -41,6 +41,11 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
while (filp->f_pos < inode->i_size) {
bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
+ if(bh==NULL)
+ {
+ printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
+ break;
+ }
i = (filp->f_pos - (((filp->f_pos >> 6) >> 3) << 9)) & 0x3f;
while (i < QNX4_INODES_PER_BLOCK) {
offset = i * QNX4_DIR_ENTRY_SIZE;
diff --git a/fs/qnx4/symlinks.c b/fs/qnx4/symlinks.c
index c360d8b72..0b3f9ae03 100644
--- a/fs/qnx4/symlinks.c
+++ b/fs/qnx4/symlinks.c
@@ -98,12 +98,12 @@ static int qnx4_readlink(struct dentry *dentry, char *buffer, int buflen)
}
bh = bread(inode->i_dev, qnx4_ino->i_first_xtnt.xtnt_blk,
QNX4_BLOCK_SIZE);
- QNX4DEBUG(("qnx4: qnx4_bread sym called -> [%s]\n",
- bh->b_data));
if (bh == NULL) {
QNX4DEBUG(("qnx4: NULL symlink bh\n"));
return 0;
}
+ QNX4DEBUG(("qnx4: qnx4_bread sym called -> [%s]\n",
+ bh->b_data));
if (bh->b_data[0] != 0) {
i = 0;
while (i < buflen && (c = bh->b_data[i])) {
diff --git a/fs/select.c b/fs/select.c
index 4cb1a6d55..3f278187e 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -64,9 +64,9 @@ void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table
if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
struct poll_table_entry * entry;
ok_table:
- entry = p->entry + p->nr;
- entry->filp = filp;
- atomic_inc(&filp->f_count);
+ entry = p->entry + p->nr;
+ get_file(filp);
+ entry->filp = filp;
entry->wait_address = wait_address;
init_waitqueue_entry(&entry->wait, current);
add_wait_queue(wait_address,&entry->wait);
@@ -164,9 +164,11 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
wait = wait_table;
}
- lock_kernel();
-
+ read_lock(&current->files->file_lock);
retval = max_select_fd(n, fds);
+ read_unlock(&current->files->file_lock);
+
+ lock_kernel();
if (retval < 0)
goto out;
n = retval;
diff --git a/fs/super.c b/fs/super.c
index 5cf518959..f70815094 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -531,6 +531,7 @@ static struct super_block *get_empty_super(void)
INIT_LIST_HEAD(&s->s_dirty);
list_add (&s->s_list, super_blocks.prev);
init_waitqueue_head(&s->s_wait);
+ INIT_LIST_HEAD(&s->s_files);
}
return s;
}
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index 3019c913f..36650f141 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -30,9 +30,6 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
-
/*
* Write to a file (through the page cache).
*/
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index b464318a7..c75a3a405 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -360,14 +360,22 @@ unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
if (result) {
for (i = 0; i < oldcount; i++) {
bh = bread (sb->s_dev, tmp + i, sb->s_blocksize);
- mark_buffer_clean (bh);
- bh->b_blocknr = result + i;
- mark_buffer_dirty (bh, 0);
- if (IS_SYNC(inode)) {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
+ if(bh)
+ {
+ mark_buffer_clean (bh);
+ bh->b_blocknr = result + i;
+ mark_buffer_dirty (bh, 0);
+ if (IS_SYNC(inode)) {
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer (bh);
+ }
+ brelse (bh);
+ }
+ else
+ {
+ printk(KERN_ERR "ufs_new_fragments: bread fail\n");
+ return 0;
}
- brelse (bh);
}
*p = SWAB32(result);
*err = 0;
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 12937adcf..b6a1f8ef6 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -467,7 +467,8 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
}
if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
printk("You didn't specify the type of your ufs filesystem\n\n"
- " mount -t ufs -o ufstype=sun|sunx86|44bsd|old|nextstep|netxstep-cd|openstep ...\n\n"
+ "mount -t ufs -o ufstype="
+ "sun|sunx86|44bsd|old|nextstep|netxstep-cd|openstep ...\n\n"
">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
"default is ufstype=old\n");
ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c
index d3d8a74e6..b930c46ae 100644
--- a/fs/umsdos/file.c
+++ b/fs/umsdos/file.c
@@ -13,7 +13,6 @@
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
-#include <linux/msdos_fs.h>
#include <linux/umsdos_fs.h>
#include <asm/uaccess.h>