lkml.org 
[lkml]   [1999]   [Jun]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: Extended f_count patch (SMP-safe handling of struct file)


On Tue, 22 Jun 1999, Alexander Viro wrote:

> News:
> * the only function in fs/file-table.c that still needs the big lock
> is fput(). And only for two calls. The rest is SMP-safe.
> * inuse_filp is no more. Instead of the one huge list we are keeping
> per-superblock lists + per-tty lists + anonymous list (pipes and sockets).
> That should speed up tty layer - it used to run through the whole list,
> procfs stuff (on proc_unregister() - it did the same) and quota (we don't
> have to traverse the whole list anymore).
> * New type: struct file_list (fs.h). Header for the file list.
> struct file contains the pointer to file_list (f_list). super_block and
> tty_struct contain struct file_list (s_files and tty_files resp.).
> * New function: file_move(struct file*, struct file_list*); moves
> the file to list. SMP-safe. If device driver wants to keep a list of files
> - fine, just move them (in ->open()) to a private list. BTW, AF_UNIX
> garbage collector will win big way from such change, but I didn't do it
> yet (per-PF lists).
>
> I'll post cleaner version this evening. Patch is against 2.3.8-pre2.

Aargh... My apologies, folks - I've posted the wrong version (which
wouldn't compile, to start with ;-/). Oh, well... Anyway, here is the
right variant after some cleanup. Against 2.3.8. Sorry about that ;-/
Wearing brown paperbag,
Al
diff -urN linux-2.3.8/arch/alpha/kernel/osf_sys.c linux-bird.f_count/arch/alpha/kernel/osf_sys.c
--- linux-2.3.8/arch/alpha/kernel/osf_sys.c Mon Jun 21 12:35:49 1999
+++ linux-bird.f_count/arch/alpha/kernel/osf_sys.c Tue Jun 22 23:12:04 1999
@@ -255,6 +255,7 @@
struct file *file = NULL;
unsigned long ret = -EBADF;

+ down(&current->mm->mmap_sem);
lock_kernel();
#if 0
if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
@@ -272,6 +273,7 @@
fput(file);
out:
unlock_kernel();
+ up(&current->mm->mmap_sem);
return ret;
}

diff -urN linux-2.3.8/arch/arm/kernel/sys_arm.c linux-bird.f_count/arch/arm/kernel/sys_arm.c
--- linux-2.3.8/arch/arm/kernel/sys_arm.c Mon Jun 21 14:09:15 1999
+++ linux-bird.f_count/arch/arm/kernel/sys_arm.c Tue Jun 22 23:12:04 1999
@@ -72,6 +72,7 @@
struct file * file = NULL;
struct mmap_arg_struct a;

+ down(&current->mm->mmap_sem);
lock_kernel();
if (copy_from_user(&a, arg, sizeof(a)))
goto out;
@@ -87,6 +88,7 @@
fput(file);
out:
unlock_kernel();
+ up(&current->mm->mmap_sem);
return error;
}

diff -urN linux-2.3.8/arch/mips/kernel/irixelf.c linux-bird.f_count/arch/mips/kernel/irixelf.c
--- linux-2.3.8/arch/mips/kernel/irixelf.c Mon Jun 21 13:32:20 1999
+++ linux-bird.f_count/arch/mips/kernel/irixelf.c Tue Jun 22 23:12:04 1999
@@ -850,13 +850,12 @@

len = 0;
file = current->files->fd[fd];
+ if (!file || !file->f_op)
+ return -EACCES;
dentry = file->f_dentry;
inode = dentry->d_inode;
elf_bss = 0;

- if (!file || !file->f_op)
- return -EACCES;
-
/* Seek to the beginning of the file. */
if (file->f_op->llseek) {
if ((error = file->f_op->llseek(file, 0, 0)) != 0)
diff -urN linux-2.3.8/arch/mips/kernel/syscall.c linux-bird.f_count/arch/mips/kernel/syscall.c
--- linux-2.3.8/arch/mips/kernel/syscall.c Mon Jun 21 12:35:57 1999
+++ linux-bird.f_count/arch/mips/kernel/syscall.c Tue Jun 22 23:12:04 1999
@@ -61,6 +61,7 @@
struct file * file = NULL;
unsigned long error = -EFAULT;

+ down(&current->mm->mmap_sem);
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
error = -EBADF;
@@ -74,6 +75,7 @@
fput(file);
out:
unlock_kernel();
+ up(&current->mm->mmap_sem);
return error;
}

diff -urN linux-2.3.8/arch/mips/kernel/sysirix.c linux-bird.f_count/arch/mips/kernel/sysirix.c
--- linux-2.3.8/arch/mips/kernel/sysirix.c Mon Jun 21 13:32:21 1999
+++ linux-bird.f_count/arch/mips/kernel/sysirix.c Tue Jun 22 23:12:04 1999
@@ -1103,6 +1103,7 @@
struct file *file = NULL;
unsigned long retval;

+ down(&current->mm->mmap_sem);
lock_kernel();
if(!(flags & MAP_ANONYMOUS)) {
if(!(file = fget(fd))) {
@@ -1130,6 +1131,7 @@

out:
unlock_kernel();
+ up(&current->mm->mmap_sem);
return retval;
}

diff -urN linux-2.3.8/arch/ppc/kernel/syscalls.c linux-bird.f_count/arch/ppc/kernel/syscalls.c
--- linux-2.3.8/arch/ppc/kernel/syscalls.c Mon Jun 21 13:32:31 1999
+++ linux-bird.f_count/arch/ppc/kernel/syscalls.c Tue Jun 22 23:12:04 1999
@@ -201,12 +201,16 @@

lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ if (!(file = fget(fd)))
goto out;
}

flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down(&current->mm->mmap_sem);
ret = do_mmap(file, addr, len, prot, flags, offset);
+ up(&current->mm->mmap_sem);
+ if (file)
+ fput(file);
out:
unlock_kernel();
return ret;
diff -urN linux-2.3.8/arch/sparc/kernel/sunos_ioctl.c linux-bird.f_count/arch/sparc/kernel/sunos_ioctl.c
--- linux-2.3.8/arch/sparc/kernel/sunos_ioctl.c Mon Jun 21 12:36:02 1999
+++ linux-bird.f_count/arch/sparc/kernel/sunos_ioctl.c Tue Jun 22 23:12:04 1999
@@ -40,7 +40,7 @@
int ret = -EBADF;

lock_kernel();
- if (fd >= SUNOS_NR_OPEN || !(filp = current->files->fd [fd]))
+ if (fd >= SUNOS_NR_OPEN || !(filp = fcheck(fd)))
goto out;

/* First handle an easy compat. case for tty ldisc. */
diff -urN linux-2.3.8/arch/sparc/mm/srmmu.c linux-bird.f_count/arch/sparc/mm/srmmu.c
--- linux-2.3.8/arch/sparc/mm/srmmu.c Mon Jun 21 12:36:02 1999
+++ linux-bird.f_count/arch/sparc/mm/srmmu.c Tue Jun 22 23:12:05 1999
@@ -2076,6 +2076,7 @@
goto done;
inode = file->f_dentry->d_inode;
offset = (address & PAGE_MASK) - vma->vm_start;
+ spin_lock(&inode->i_shared_lock);
vmaring = inode->i_mmap;
do {
/* Do not mistake ourselves as another mapping. */
@@ -2109,6 +2110,7 @@
}
}
} while ((vmaring = vmaring->vm_next_share) != NULL);
+ spin_unlock(&inode->i_shared_lock);

if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) {
pgdp = srmmu_pgd_offset(vma->vm_mm, address);
diff -urN linux-2.3.8/arch/sparc/mm/sun4c.c linux-bird.f_count/arch/sparc/mm/sun4c.c
--- linux-2.3.8/arch/sparc/mm/sun4c.c Mon Jun 21 12:36:02 1999
+++ linux-bird.f_count/arch/sparc/mm/sun4c.c Tue Jun 22 23:12:05 1999
@@ -2682,8 +2682,10 @@
inode = dentry->d_inode;
if(inode) {
unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
- struct vm_area_struct *vmaring = inode->i_mmap;
+ struct vm_area_struct *vmaring;
int alias_found = 0;
+ spin_lock(&inode->i_shared_lock);
+ vmaring = inode->i_mmap;
do {
unsigned long vaddr = vmaring->vm_start + offset;
unsigned long start;
@@ -2712,6 +2714,7 @@
}
}
} while ((vmaring = vmaring->vm_next_share) != NULL);
+ spin_unlock(&inode->i_shared_lock);

if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
pgdp = sun4c_pgd_offset(vma->vm_mm, address);
diff -urN linux-2.3.8/arch/sparc64/kernel/sys_sparc32.c linux-bird.f_count/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.3.8/arch/sparc64/kernel/sys_sparc32.c Mon Jun 21 13:42:00 1999
+++ linux-bird.f_count/arch/sparc64/kernel/sys_sparc32.c Wed Jun 23 00:02:07 1999
@@ -2335,8 +2335,8 @@
break;
}
/* Bump the usage count and install the file. */
- fp[i]->f_count++;
- current->files->fd[new_fd] = fp[i];
+ get_file(fp[i]);
+ fd_install(new_fd, fp[i]);
}

if (i > 0) {
diff -urN linux-2.3.8/arch/sparc64/kernel/sys_sunos32.c linux-bird.f_count/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.3.8/arch/sparc64/kernel/sys_sunos32.c Mon Jun 21 14:09:57 1999
+++ linux-bird.f_count/arch/sparc64/kernel/sys_sunos32.c Tue Jun 22 23:12:05 1999
@@ -712,7 +712,7 @@
struct inode *inode;
struct file *file;

- file = current->files->fd [fd];
+ file = fcheck(fd);
if(!file)
return 0;

diff -urN linux-2.3.8/arch/sparc64/solaris/misc.c linux-bird.f_count/arch/sparc64/solaris/misc.c
--- linux-2.3.8/arch/sparc64/solaris/misc.c Mon Jun 21 12:36:05 1999
+++ linux-bird.f_count/arch/sparc64/solaris/misc.c Tue Jun 22 23:12:05 1999
@@ -83,6 +83,7 @@
}
}

+ down(&current->mm->mmap_sem);
retval = -ENOMEM;
if(!(flags & MAP_FIXED) && !addr) {
unsigned long attempt = get_unmapped_area(addr, len);
@@ -102,6 +103,7 @@
if(!ret_type)
retval = ((retval < 0xf0000000) ? 0 : retval);
out_putf:
+ up(&current->mm->mmap_sem);
if (file)
fput(file);
out:
diff -urN linux-2.3.8/drivers/block/loop.c linux-bird.f_count/drivers/block/loop.c
--- linux-2.3.8/drivers/block/loop.c Mon Jun 21 13:19:53 1999
+++ linux-bird.f_count/drivers/block/loop.c Tue Jun 22 23:12:05 1999
@@ -391,6 +391,7 @@
lo->lo_backing_file->f_dentry = file->f_dentry;
lo->lo_backing_file->f_op = file->f_op;
lo->lo_backing_file->private_data = file->private_data;
+ file_move(lo->lo_backing_file, file->f_list);

error = get_write_access(inode);
if (error) {
diff -urN linux-2.3.8/drivers/char/sysrq.c linux-bird.f_count/drivers/char/sysrq.c
--- linux-2.3.8/drivers/char/sysrq.c Mon Jun 21 12:36:12 1999
+++ linux-bird.f_count/drivers/char/sysrq.c Wed Jun 23 00:03:26 1999
@@ -150,15 +150,6 @@

/* Aux routines for the syncer */

-static void all_files_read_only(void) /* Kill write permissions of all files */
-{
- struct file *file;
-
- for (file = inuse_filps; file; file = file->f_next)
- if (file->f_dentry && file->f_count && S_ISREG(file->f_dentry->d_inode->i_mode))
- file->f_mode &= ~2;
-}
-
static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard drive */
{
unsigned int major = MAJOR(dev);
@@ -192,6 +183,7 @@
struct super_block *sb = get_super(dev);
struct vfsmount *vfsmnt;
int ret, flags;
+ struct file *file;

if (!sb) {
printk("Superblock not found\n");
@@ -201,6 +193,13 @@
printk("R/O\n");
return;
}
+
+ spin_lock(&sb->s_files.fl_lock);
+ for (file = sb->s_files.fl_list; file; file = file->f_next)
+ if (file->f_dentry && file_count(file)
+ && S_ISREG(file->f_dentry->d_inode->i_mode))
+ file->f_mode &= ~2;
+ spin_unlock(&sb->s_files.fl_lock);
DQUOT_OFF(dev);
fsync_dev(dev);
flags = MS_RDONLY;
@@ -239,9 +238,6 @@
lock_kernel();
remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
emergency_sync_scheduled = 0;
-
- if (remount_flag)
- all_files_read_only();

for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
if (is_local_disk(mnt->mnt_dev))
diff -urN linux-2.3.8/drivers/char/tpqic02.c linux-bird.f_count/drivers/char/tpqic02.c
--- linux-2.3.8/drivers/char/tpqic02.c Mon Jun 21 12:49:55 1999
+++ linux-bird.f_count/drivers/char/tpqic02.c Wed Jun 23 00:03:43 1999
@@ -2216,7 +2216,7 @@
}

/* Only one at a time from here on... */
- if (filp->f_count>1) /* filp->f_count==1 for the first open() */
+ if (file_count(filp)>1) /* filp->f_count==1 for the first open() */
{
return -EBUSY;
}
diff -urN linux-2.3.8/drivers/char/tty_io.c linux-bird.f_count/drivers/char/tty_io.c
--- linux-2.3.8/drivers/char/tty_io.c Mon Jun 21 13:56:26 1999
+++ linux-bird.f_count/drivers/char/tty_io.c Tue Jun 22 23:12:06 1999
@@ -176,10 +176,12 @@
struct file *f;
int count = 0;

- for(f = inuse_filps; f; f = f->f_next) {
+ spin_lock(&tty->tty_files.fl_lock);
+ for(f = tty->tty_files.fl_list; f; f = f->f_next) {
if(f->private_data == tty)
count++;
}
+ spin_unlock(&tty->tty_files.fl_lock);
if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
tty->driver.subtype == PTY_TYPE_SLAVE &&
tty->link && tty->link->count)
@@ -395,13 +397,10 @@
lock_kernel();

check_tty_count(tty, "do_tty_hangup");
- for (filp = inuse_filps; filp; filp = filp->f_next) {
- if (filp->private_data != tty)
- continue;
+ spin_lock(&tty->tty_files.fl_lock);
+ for (filp = tty->tty_files.fl_list; filp; filp = filp->f_next) {
if (!filp->f_dentry)
continue;
- if (!filp->f_dentry->d_inode)
- continue;
if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) {
cons_filp = filp;
@@ -410,9 +409,10 @@
if (filp->f_op != &tty_fops)
continue;
closecount++;
- tty_fasync(-1, filp, 0);
+ tty_fasync(-1, filp, 0); /* can't block */
filp->f_op = &hung_up_tty_fops;
}
+ spin_unlock(&tty->tty_files.fl_lock);

/* FIXME! What are the locking issues here? This may me overdoing things.. */
{
@@ -1303,6 +1303,7 @@
init_dev_done:
#endif
filp->private_data = tty;
+ file_move(filp, &tty->tty_files);
check_tty_count(tty, "tty_open");
if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
tty->driver.subtype == PTY_TYPE_MASTER)
@@ -1933,6 +1934,8 @@
tty->tq_hangup.routine = do_tty_hangup;
tty->tq_hangup.data = tty;
sema_init(&tty->atomic_read, 1);
+ spin_lock_init(&tty->tty_files.fl_lock);
+ tty->tty_files.fl_list = NULL;
}

/*
diff -urN linux-2.3.8/drivers/scsi/st.c linux-bird.f_count/drivers/scsi/st.c
--- linux-2.3.8/drivers/scsi/st.c Mon Jun 21 13:12:01 1999
+++ linux-bird.f_count/drivers/scsi/st.c Wed Jun 23 00:04:01 1999
@@ -890,7 +890,7 @@
kdev_t devt = inode->i_rdev;
int dev;

- if (filp->f_count > 1)
+ if (file_count(filp) > 1)
return 0;

dev = TAPE_NR(devt);
diff -urN linux-2.3.8/drivers/sgi/char/usema.c linux-bird.f_count/drivers/sgi/char/usema.c
--- linux-2.3.8/drivers/sgi/char/usema.c Mon Jun 21 13:07:41 1999
+++ linux-bird.f_count/drivers/sgi/char/usema.c Wed Jun 23 01:08:04 1999
@@ -50,8 +50,8 @@
if (newfd < 0)
return newfd;

- current->files->fd [newfd] = usema->filp;
- usema->filp->f_count++;
+ get_file(usema);
+ fd_install(newfd, usema->filp);
/* Is that it? */
printk("UIOCATTACHSEMA: new usema fd is %d", newfd);
return newfd;
diff -urN linux-2.3.8/fs/dquot.c linux-bird.f_count/fs/dquot.c
--- linux-2.3.8/fs/dquot.c Mon Jun 21 12:55:30 1999
+++ linux-bird.f_count/fs/dquot.c Tue Jun 22 23:12:06 1999
@@ -583,20 +583,22 @@
if (!sb || !sb->dq_op)
return; /* nothing to do */

- for (filp = inuse_filps; filp; filp = filp->f_next) {
+ spin_lock(&sb->s_files.fl_lock);
+ for (filp = sb->s_files.fl_list; filp; filp = filp->f_next) {
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) {
+ spin_unlock(&sb->s_files.fl_lock);
sb->dq_op->initialize(inode, type);
inode->i_flags |= S_QUOTA;
+ spin_lock(&sb->s_files.fl_lock);
}
}
+ spin_unlock(&sb->s_files.fl_lock);
}

static void reset_dquot_ptrs(kdev_t dev, short type)
@@ -614,11 +616,10 @@
/* free any quota for unused dentries */
shrink_dcache_sb(sb);

- for (filp = inuse_filps; filp; filp = filp->f_next) {
+ spin_lock(&sb->s_files.fl_lock);
+ for (filp = sb->s_files.fl_list; filp; filp = filp->f_next) {
if (!filp->f_dentry)
continue;
- if (filp->f_dentry->d_sb != sb)
- continue;
inode = filp->f_dentry->d_inode;
if (!inode)
continue;
@@ -637,12 +638,14 @@
inode->i_flags &= ~S_QUOTA;
put_it:
if (dquot != NODQUOT) {
+ spin_unlock(&sb->s_files.fl_lock);
dqput(dquot);
/* we may have blocked ... */
goto restart;
}
}
}
+ spin_unlock(&sb->s_files.fl_lock);
}

static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
diff -urN linux-2.3.8/fs/exec.c linux-bird.f_count/fs/exec.c
--- linux-2.3.8/fs/exec.c Mon Jun 21 13:30:15 1999
+++ linux-bird.f_count/fs/exec.c Tue Jun 22 23:12:06 1999
@@ -123,8 +123,12 @@
{
struct inode * inode = dentry->d_inode;
struct file * f;
+ struct file_list * 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;
@@ -145,6 +149,7 @@
if (error)
goto out_filp;
}
+ file_move(f, l);
fd_install(fd, f);
dget(dentry);
}
@@ -563,7 +568,8 @@
if ((retval = permission(inode, MAY_EXEC)) != 0)
return retval;
/* better not execute files which are being written to */
- if (inode->i_writecount > 0)
+ /* WARNING. Read comments in fs/namei.c::get_write_access() */
+ if (atomic_read(&inode->i_writecount) > 0)
return -ETXTBSY;

bprm->e_uid = current->euid;
diff -urN linux-2.3.8/fs/file_table.c linux-bird.f_count/fs/file_table.c
--- linux-2.3.8/fs/file_table.c Mon Jun 21 13:30:15 1999
+++ linux-bird.f_count/fs/file_table.c Tue Jun 22 23:12:06 1999
@@ -18,27 +18,21 @@
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;
+/* Here the new files go */
+static struct file_list anon_list = { NULL, SPIN_LOCK_UNLOCKED };
+/* And here the free ones sit */
+static struct file_list free_list = { NULL, SPIN_LOCK_UNLOCKED };
+
+static void insert_file_list(struct file *file, struct file_list *list,
+ int *count)
+{
+ spin_lock(&list->fl_lock);
+ if ( (file->f_next = list->fl_list) != NULL)
+ list->fl_list->f_pprev = &file->f_next;
+ list->fl_list = file;
+ file->f_pprev = &list->fl_list;
+ if (count) (*count)++;
+ spin_unlock(&list->fl_lock);
}

/* It does not matter which list it is on. */
@@ -67,24 +61,28 @@
/* 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;

+ spin_lock(&free_list.fl_lock);
if (nr_free_files > NR_RESERVED_FILES) {
used_one:
- f = free_filps;
+ f = free_list.fl_list;
remove_filp(f);
nr_free_files--;
new_one:
+ spin_unlock(&free_list.fl_lock);
memset(f, 0, sizeof(*f));
- 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);
+ insert_file_list(f, &anon_list, NULL);
return f;
}
/*
@@ -96,7 +94,9 @@
* Allocate a new one if we're below the limit.
*/
if (nr_files < max_files) {
+ spin_unlock(&free_list.fl_lock);
f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
+ spin_lock(&free_list.fl_lock);
if (f) {
nr_files++;
goto new_one;
@@ -108,6 +108,7 @@
printk("VFS: file-max limit %d reached\n", max_files);
old_max = max_files;
}
+ spin_unlock(&free_list.fl_lock);
return NULL;
}

@@ -120,7 +121,7 @@
{
memset(filp, 0, sizeof(*filp));
filp->f_mode = mode;
- filp->f_count = 1;
+ atomic_set(&filp->f_count, 1);
filp->f_dentry = dentry;
filp->f_uid = current->fsuid;
filp->f_gid = current->fsgid;
@@ -133,22 +134,69 @@

void fput(struct file *file)
{
- int count = file->f_count-1;
+ if (atomic_dec_and_test(&file->f_count)) {
+ struct file_list *list;
+ atomic_inc(&file->f_count);
+ list = file->f_list;
+
+ locks_remove_flock(file); /* Still need the */
+ __fput(file); /* big lock here. */

- if (!count) {
- locks_remove_flock(file);
- __fput(file);
- file->f_count = 0;
+ atomic_set(&file->f_count, 0);
+ spin_lock(&list->fl_lock);
remove_filp(file);
- insert_file_free(file);
- } else
- file->f_count = count;
+ spin_unlock(&list->fl_lock);
+ insert_file_list(file, &free_list, &nr_free_files);
+ }
}

+/* Here. put_filp() is SMP-safe now. */
+
void put_filp(struct file *file)
{
- if(--file->f_count == 0) {
+ if(atomic_dec_and_test(&file->f_count)) {
+ struct file_list *list = file->f_list;
+ spin_lock(&list->fl_lock);
remove_filp(file);
- insert_file_free(file);
+ spin_unlock(&list->fl_lock);
+ insert_file_list(file, &free_list, &nr_free_files);
+ }
+}
+
+void file_move(struct file *file, struct file_list *list)
+{
+ struct file_list *old_list = file->f_list;
+ if (!list || list == old_list)
+ return;
+ spin_lock(&old_list->fl_lock);
+ remove_filp(file);
+ spin_unlock(&old_list->fl_lock);
+ insert_file_list(file, list, NULL);
+}
+
+int fs_may_remount_ro(struct super_block *sb)
+{
+ struct file *file;
+
+ /* Check that no files are currently opened for writing. */
+ spin_lock(&sb->s_files.fl_lock);
+ for (file = sb->s_files.fl_list; file; file = file->f_next) {
+ struct inode *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;
}
+ spin_unlock(&sb->s_files.fl_lock);
+ return 1; /* Tis' cool bro. */
+too_bad:
+ spin_unlock(&sb->s_files.fl_lock);
+ return 0;
}
diff -urN linux-2.3.8/fs/hpfs/mmap.c linux-bird.f_count/fs/hpfs/mmap.c
--- linux-2.3.8/fs/hpfs/mmap.c Mon Jun 21 13:03:49 1999
+++ linux-bird.f_count/fs/hpfs/mmap.c Wed Jun 23 00:06:03 1999
@@ -99,30 +99,3 @@
NULL, /* swapout */
NULL, /* swapin */
};
-
-/*
- * This is used for a general mmap of an msdos file
- * Returns 0 if ok, or a negative error code if not.
- */
-int hpfs_mmap(struct file * file, struct vm_area_struct * vma)
-{
- struct inode *inode = file->f_dentry->d_inode;
- /*printk("start mmap\n");*/
- if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */
- return -EINVAL;
- if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
- return -EINVAL;
- if (!inode->i_sb || !S_ISREG(inode->i_mode))
- return -EACCES;
- /*if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }*/
-
- vma->vm_file = file;
- /*inode->i_count++;*/
- file->f_count++;
- vma->vm_ops = &hpfs_file_mmap;
- /*printk("end mmap\n");*/
- return 0;
-}
diff -urN linux-2.3.8/fs/inode.c linux-bird.f_count/fs/inode.c
--- linux-2.3.8/fs/inode.c Mon Jun 21 14:12:09 1999
+++ linux-bird.f_count/fs/inode.c Tue Jun 22 23:12:06 1999
@@ -130,6 +130,7 @@
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)
@@ -521,7 +522,7 @@
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));
@@ -806,31 +807,6 @@
if (max > MAX_INODE)
max = MAX_INODE;
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)
diff -urN linux-2.3.8/fs/locks.c linux-bird.f_count/fs/locks.c
--- linux-2.3.8/fs/locks.c Tue Jun 22 22:07:29 1999
+++ linux-bird.f_count/fs/locks.c Tue Jun 22 23:12:06 1999
@@ -400,16 +400,23 @@

/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
+ *
+ * Since do_mmap() is protected by big lock we are safe here, but as
+ * soon as it will go we will have a bunch of interesting stuff to
+ * care of.
*/
if (IS_MANDLOCK(inode) &&
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
inode->i_mmap) {
- struct vm_area_struct *vma = inode->i_mmap;
+ struct vm_area_struct *vma;
error = -EAGAIN;
+ spin_lock(&inode->i_shared_lock);
+ vma = inode->i_mmap;
do {
if (vma->vm_flags & VM_MAYSHARE)
- goto out_putf;
+ goto out_putf_unlock;
} while ((vma = vma->vm_next_share) != NULL);
+ spin_unlock(&inode->i_shared_lock);
}

error = -EINVAL;
@@ -461,6 +468,9 @@
fput(filp);
out:
return error;
+out_putf_unlock:
+ spin_unlock(&inode->i_shared_lock);
+ goto out_putf;
}

/*
diff -urN linux-2.3.8/fs/namei.c linux-bird.f_count/fs/namei.c
--- linux-2.3.8/fs/namei.c Mon Jun 21 13:07:59 1999
+++ linux-bird.f_count/fs/namei.c Tue Jun 22 23:12:06 1999
@@ -171,18 +171,22 @@
* 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 -urN linux-2.3.8/fs/nfs/write.c linux-bird.f_count/fs/nfs/write.c
--- linux-2.3.8/fs/nfs/write.c Mon Jun 21 14:31:25 1999
+++ linux-bird.f_count/fs/nfs/write.c Wed Jun 23 01:08:50 1999
@@ -305,6 +305,7 @@
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 @@
* The IO completion will then free the page and the dentry.
*/
get_page(page);
- file->f_count++;

/* Schedule request */
synchronous = schedule_write_request(req, synchronous);
diff -urN linux-2.3.8/fs/nfsd/vfs.c linux-bird.f_count/fs/nfsd/vfs.c
--- linux-2.3.8/fs/nfsd/vfs.c Mon Jun 21 13:08:12 1999
+++ linux-bird.f_count/fs/nfsd/vfs.c Tue Jun 22 23:12:07 1999
@@ -342,7 +342,7 @@

memset(filp, 0, sizeof(*filp));
filp->f_op = inode->i_op->default_file_ops;
- filp->f_count = 1;
+ atomic_set(&filp->f_count, 1);
filp->f_flags = wflag? O_WRONLY : O_RDONLY;
filp->f_mode = wflag? FMODE_WRITE : FMODE_READ;
filp->f_dentry = dentry;
@@ -360,7 +360,7 @@
/* I nearly added put_filp() call here, but this filp
* is really on callers stack frame. -DaveM
*/
- filp->f_count--;
+ atomic_dec(&filp->f_count);
}
}
out_nfserr:
@@ -585,7 +585,7 @@
* 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 -urN linux-2.3.8/fs/open.c linux-bird.f_count/fs/open.c
--- linux-2.3.8/fs/open.c Mon Jun 21 13:12:23 1999
+++ linux-bird.f_count/fs/open.c Wed Jun 23 00:05:22 1999
@@ -663,6 +663,8 @@
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)
@@ -790,7 +792,7 @@
int retval;
struct dentry *dentry = filp->f_dentry;

- if (filp->f_count == 0) {
+ if (file_count(filp) == 0) {
printk("VFS: Close: file count is 0\n");
return 0;
}
diff -urN linux-2.3.8/fs/proc/inode.c linux-bird.f_count/fs/proc/inode.c
--- linux-2.3.8/fs/proc/inode.c Mon Jun 21 13:39:45 1999
+++ linux-bird.f_count/fs/proc/inode.c Tue Jun 22 23:12:07 1999
@@ -87,13 +87,26 @@
}
}

+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 @@
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;

diff -urN linux-2.3.8/fs/proc/root.c linux-bird.f_count/fs/proc/root.c
--- linux-2.3.8/fs/proc/root.c Mon Jun 21 14:31:30 1999
+++ linux-bird.f_count/fs/proc/root.c Tue Jun 22 23:12:07 1999
@@ -366,23 +366,34 @@
static void proc_kill_inodes(int ino)
{
struct file *filp;
+ struct super_block *sb;

- /* inuse_filps is protected by the single kernel lock */
- for (filp = inuse_filps; filp; filp = filp->f_next) {
- struct dentry * dentry;
- struct inode * inode;
+ /*
+ * 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) {
+ spin_lock(&sb->s_files.fl_lock);
+ for (filp = sb->s_files.fl_list; 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;
+ 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;
+ }
+ spin_unlock(&sb->s_files.fl_lock);
}
}

diff -urN linux-2.3.8/fs/select.c linux-bird.f_count/fs/select.c
--- linux-2.3.8/fs/select.c Mon Jun 21 13:12:24 1999
+++ linux-bird.f_count/fs/select.c Wed Jun 23 01:08:26 1999
@@ -65,8 +65,8 @@
struct poll_table_entry * entry;
ok_table:
entry = p->entry + p->nr;
+ get_file(filp);
entry->filp = filp;
- filp->f_count++;
entry->wait_address = wait_address;
init_waitqueue_entry(&entry->wait, current);
add_wait_queue(wait_address,&entry->wait);
diff -urN linux-2.3.8/fs/super.c linux-bird.f_count/fs/super.c
--- linux-2.3.8/fs/super.c Mon Jun 21 14:12:10 1999
+++ linux-bird.f_count/fs/super.c Tue Jun 22 23:12:07 1999
@@ -531,6 +531,8 @@
INIT_LIST_HEAD(&s->s_dirty);
list_add (&s->s_list, super_blocks.prev);
init_waitqueue_head(&s->s_wait);
+ spin_lock_init(&s->s_files.fl_lock);
+ s->s_files.fl_list = NULL;
}
return s;
}
diff -urN linux-2.3.8/include/linux/file.h linux-bird.f_count/include/linux/file.h
--- linux-2.3.8/include/linux/file.h Mon Jun 21 13:40:25 1999
+++ linux-bird.f_count/include/linux/file.h Wed Jun 23 01:08:59 1999
@@ -32,12 +32,13 @@
return file;
}

+/* Still needs a protection against modifications of current->files->fd[] */
extern inline struct file * fget(unsigned int fd)
{
struct file * file = fcheck(fd);

if (file)
- file->f_count++;
+ get_file(file);
return file;
}

diff -urN linux-2.3.8/include/linux/fs.h linux-bird.f_count/include/linux/fs.h
--- linux-2.3.8/include/linux/fs.h Tue Jun 22 22:07:30 1999
+++ linux-bird.f_count/include/linux/fs.h Wed Jun 23 00:44:03 1999
@@ -234,13 +234,30 @@
typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
void init_buffer(struct buffer_head *, kdev_t, int, bh_end_io_t *, void *);

-#define __buffer_state(bh, state) (((bh)->b_state & (1UL << BH_##state)) != 0)
+static inline int buffer_uptodate(struct buffer_head * bh)
+{
+ return test_bit(BH_Uptodate, &bh->b_state);
+}
+
+static inline int buffer_dirty(struct buffer_head * bh)
+{
+ return test_bit(BH_Dirty, &bh->b_state);
+}
+
+static inline int buffer_locked(struct buffer_head * bh)
+{
+ return test_bit(BH_Lock, &bh->b_state);
+}
+
+static inline int buffer_req(struct buffer_head * bh)
+{
+ return test_bit(BH_Req, &bh->b_state);
+}

-#define buffer_uptodate(bh) __buffer_state(bh,Uptodate)
-#define buffer_dirty(bh) __buffer_state(bh,Dirty)
-#define buffer_locked(bh) __buffer_state(bh,Lock)
-#define buffer_req(bh) __buffer_state(bh,Req)
-#define buffer_protected(bh) __buffer_state(bh,Protected)
+static inline int buffer_protected(struct buffer_head * bh)
+{
+ return test_bit(BH_Protected, &bh->b_state);
+}

#define buffer_page(bh) (mem_map + MAP_NR((bh)->b_data))
#define touch_buffer(bh) set_bit(PG_referenced, &buffer_page(bh)->flags)
@@ -345,6 +362,7 @@
struct file_lock *i_flock;
struct vm_area_struct *i_mmap;
struct page *i_pages;
+ spinlock_t i_shared_lock;
struct dquot *i_dquot[MAXQUOTAS];
struct pipe_inode_info *i_pipe;

@@ -353,7 +371,7 @@
unsigned int i_flags;
unsigned char i_sock;

- int i_writecount;
+ atomic_t i_writecount;
unsigned int i_attr_flags;
__u32 i_generation;
union {
@@ -404,7 +422,8 @@
struct file_operations *f_op;
mode_t f_mode;
loff_t f_pos;
- unsigned int f_count, f_flags;
+ atomic_t f_count;
+ unsigned int f_flags;
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
@@ -414,8 +433,13 @@

/* needed for tty driver, and maybe others */
void *private_data;
+ struct file_list *f_list; /* pointer back to the list */
};

+#define get_file(x) atomic_inc(&(x)->f_count)
+#define triple_file(x) atomic_add(2, &(x)->f_count)
+#define file_count(x) atomic_read(&(x)->f_count)
+
extern int init_private_file(struct file *, struct dentry *, int);

#define FL_POSIX 1
@@ -481,6 +505,11 @@

extern int fasync_helper(int, struct file *, int, struct fasync_struct **);

+struct file_list {
+ struct file * fl_list;
+ spinlock_t fl_lock;
+};
+
#include <linux/minix_fs_sb.h>
#include <linux/ext2_fs_sb.h>
#include <linux/hpfs_fs_sb.h>
@@ -522,6 +551,7 @@
short int s_ibasket_count;
short int s_ibasket_max;
struct list_head s_dirty; /* dirty inodes */
+ struct file_list s_files;

union {
struct minix_sb_info minix_sb;
@@ -736,8 +766,6 @@
extern int fs_may_remount_ro(struct super_block *);
extern int fs_may_mount(kdev_t);

-extern struct file *inuse_filps;
-
extern int try_to_free_buffers(struct page *);
extern void refile_buffer(struct buffer_head * buf);

@@ -845,6 +873,7 @@
extern void insert_inode_hash(struct inode *);
extern void remove_inode_hash(struct inode *);
extern struct file * get_empty_filp(void);
+extern void file_move(struct file *f, struct file_list *list);
extern struct buffer_head * get_hash_table(kdev_t, int, int);
extern struct buffer_head * getblk(kdev_t, int, int);
extern struct buffer_head * find_buffer(kdev_t, int, int);
diff -urN linux-2.3.8/include/linux/net.h linux-bird.f_count/include/linux/net.h
--- linux-2.3.8/include/linux/net.h Mon Jun 21 12:40:25 1999
+++ linux-bird.f_count/include/linux/net.h Wed Jun 23 00:39:05 1999
@@ -107,6 +107,7 @@
unsigned long arg);
int (*sendmsg) (struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm);
int (*recvmsg) (struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm);
+ void (*bind_file) (struct socket *sock, struct file *file);
};

struct net_proto_family
diff -urN linux-2.3.8/include/linux/proc_fs.h linux-bird.f_count/include/linux/proc_fs.h
--- linux-2.3.8/include/linux/proc_fs.h Mon Jun 21 14:27:29 1999
+++ linux-bird.f_count/include/linux/proc_fs.h Wed Jun 23 00:44:09 1999
@@ -374,6 +374,7 @@
}
}

+extern struct super_block *proc_super_blocks;
extern struct dentry_operations proc_dentry_operations;
extern struct super_block *proc_read_super(struct super_block *,void *,int);
extern int init_proc_fs(void);
diff -urN linux-2.3.8/include/linux/tty.h linux-bird.f_count/include/linux/tty.h
--- linux-2.3.8/include/linux/tty.h Mon Jun 21 12:40:29 1999
+++ linux-bird.f_count/include/linux/tty.h Wed Jun 23 00:44:09 1999
@@ -277,6 +277,7 @@
struct tq_struct tq_hangup;
void *disc_data;
void *driver_data;
+ struct file_list tty_files;

#define N_TTY_BUF_SIZE 4096

diff -urN linux-2.3.8/include/net/af_unix.h linux-bird.f_count/include/net/af_unix.h
--- linux-2.3.8/include/net/af_unix.h Mon Jun 21 12:37:01 1999
+++ linux-bird.f_count/include/net/af_unix.h Tue Jun 22 23:12:08 1999
@@ -6,6 +6,7 @@
extern void unix_notinflight(struct file *fp);
typedef struct sock unix_socket;
extern void unix_gc(void);
+extern struct file_list AF_UNIX_files;

#define UNIX_HASH_SIZE 16

diff -urN linux-2.3.8/include/net/sock.h linux-bird.f_count/include/net/sock.h
--- linux-2.3.8/include/net/sock.h Mon Jun 21 13:17:56 1999
+++ linux-bird.f_count/include/net/sock.h Wed Jun 23 00:48:20 1999
@@ -104,7 +104,6 @@
struct sock * other;
struct sock ** list;
struct sock * gc_tree;
- int inflight;
atomic_t user_count;
};

diff -urN linux-2.3.8/ipc/shm.c linux-bird.f_count/ipc/shm.c
--- linux-2.3.8/ipc/shm.c Mon Jun 21 13:50:07 1999
+++ linux-bird.f_count/ipc/shm.c Tue Jun 22 23:12:08 1999
@@ -547,6 +547,7 @@
unsigned int id;
struct shmid_kernel *shp;

+ lock_kernel();
id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
shp = shm_segs[id];
if (shp == IPC_UNUSED) {
@@ -557,6 +558,7 @@
shp->u.shm_nattch++;
shp->u.shm_atime = CURRENT_TIME;
shp->u.shm_lpid = current->pid;
+ unlock_kernel();
}

/*
@@ -570,6 +572,7 @@
struct shmid_kernel *shp;
int id;

+ lock_kernel();
/* remove from the list of attaches of the shm segment */
id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
shp = shm_segs[id];
@@ -578,6 +581,7 @@
shp->u.shm_dtime = CURRENT_TIME;
if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
killseg (id);
+ unlock_kernel();
}

/*
diff -urN linux-2.3.8/kernel/acct.c linux-bird.f_count/kernel/acct.c
--- linux-2.3.8/kernel/acct.c Mon Jun 21 14:18:12 1999
+++ linux-bird.f_count/kernel/acct.c Wed Jun 23 01:09:07 1999
@@ -276,7 +276,7 @@
*/
if (!file)
return 0;
- file->f_count++;
+ get_file(file);
if (!check_free_space(file)) {
fput(file);
return 0;
diff -urN linux-2.3.8/kernel/exit.c linux-bird.f_count/kernel/exit.c
--- linux-2.3.8/kernel/exit.c Mon Jun 21 12:40:36 1999
+++ linux-bird.f_count/kernel/exit.c Tue Jun 22 23:12:08 1999
@@ -166,11 +166,9 @@
break;
while (set) {
if (set & 1) {
- struct file * file = files->fd[i];
- if (file) {
- files->fd[i] = NULL;
+ struct file * file = xchg(&files->fd[i], NULL);
+ if (file)
filp_close(file, files);
- }
}
i++;
set >>= 1;
diff -urN linux-2.3.8/kernel/fork.c linux-bird.f_count/kernel/fork.c
--- linux-2.3.8/kernel/fork.c Tue Jun 22 22:07:30 1999
+++ linux-bird.f_count/kernel/fork.c Wed Jun 23 01:09:59 1999
@@ -243,22 +243,28 @@
if (!tmp)
goto fail_nomem;
*tmp = *mpnt;
+ /*
+ * Accurate here. We need to be sure that nothing will
+ * alter mpnt->vm_file before we increment f_count.
+ */
tmp->vm_flags &= ~VM_LOCKED;
tmp->vm_mm = mm;
mm->map_count++;
tmp->vm_next = NULL;
file = tmp->vm_file;
if (file) {
- file->f_count++;
+ get_file(file);
if (tmp->vm_flags & VM_DENYWRITE)
- file->f_dentry->d_inode->i_writecount--;
+ atomic_dec(&file->f_dentry->d_inode->i_writecount);

+ spin_lock(&file->f_dentry->d_inode->i_shared_lock);
/* insert tmp into the share list, just after mpnt */
if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
mpnt->vm_next_share->vm_pprev_share =
&tmp->vm_next_share;
mpnt->vm_next_share = tmp;
tmp->vm_pprev_share = &mpnt->vm_next_share;
+ spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
}

/* Copy the pages, but defer checking for errors */
@@ -483,9 +489,9 @@
old_fds = oldf->fd;
for (; i != 0; i--) {
struct file *f = *old_fds++;
- *new_fds = f;
if (f)
- f->f_count++;
+ get_file(f);
+ *new_fds = f;
new_fds++;
}
/* This is long word aligned thus could use a optimized version */
diff -urN linux-2.3.8/mm/filemap.c linux-bird.f_count/mm/filemap.c
--- linux-2.3.8/mm/filemap.c Tue Jun 22 22:07:30 1999
+++ linux-bird.f_count/mm/filemap.c Wed Jun 23 01:10:09 1999
@@ -1481,7 +1481,7 @@
* If a task terminates while we're swapping the page, the vma and
* and file could be released ... increment the count to be safe.
*/
- file->f_count++;
+ get_file(file);
result = do_write_page(inode, file, (const char *) page, offset);
fput(file);
return result;
diff -urN linux-2.3.8/mm/memory.c linux-bird.f_count/mm/memory.c
--- linux-2.3.8/mm/memory.c Mon Jun 21 13:50:10 1999
+++ linux-bird.f_count/mm/memory.c Tue Jun 22 23:12:08 1999
@@ -723,8 +723,9 @@
struct vm_area_struct * mpnt;

truncate_inode_pages(inode, offset);
+ spin_lock(&inode->i_shared_lock);
if (!inode->i_mmap)
- return;
+ goto out_unlock;
mpnt = inode->i_mmap;
do {
struct mm_struct *mm = mpnt->vm_mm;
@@ -755,6 +756,8 @@
zap_page_range(mm, start, len);
flush_tlb_range(mm, start, end);
} while ((mpnt = mpnt->vm_next_share) != NULL);
+out_unlock:
+ spin_unlock(&inode->i_shared_lock);
}


diff -urN linux-2.3.8/mm/mlock.c linux-bird.f_count/mm/mlock.c
--- linux-2.3.8/mm/mlock.c Mon Jun 21 13:09:09 1999
+++ linux-bird.f_count/mm/mlock.c Wed Jun 23 01:14:35 1999
@@ -31,7 +31,7 @@
vma->vm_offset += vma->vm_start - n->vm_start;
n->vm_flags = newflags;
if (n->vm_file)
- n->vm_file->f_count++;
+ get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
insert_vm_struct(current->mm, n);
@@ -52,7 +52,7 @@
n->vm_offset += n->vm_start - vma->vm_start;
n->vm_flags = newflags;
if (n->vm_file)
- n->vm_file->f_count++;
+ get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
insert_vm_struct(current->mm, n);
@@ -82,7 +82,7 @@
right->vm_offset += right->vm_start - left->vm_start;
vma->vm_flags = newflags;
if (vma->vm_file)
- vma->vm_file->f_count += 2;
+ triple_file(vma->vm_file);

if (vma->vm_ops && vma->vm_ops->open) {
vma->vm_ops->open(left);
@@ -179,7 +179,6 @@
int error = -ENOMEM;

down(&current->mm->mmap_sem);
- lock_kernel();
len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
start &= PAGE_MASK;

@@ -200,7 +199,6 @@

error = do_mlock(start, len, 1);
out:
- unlock_kernel();
up(&current->mm->mmap_sem);
return error;
}
@@ -210,11 +208,9 @@
int ret;

down(&current->mm->mmap_sem);
- lock_kernel();
len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
start &= PAGE_MASK;
ret = do_mlock(start, len, 0);
- unlock_kernel();
up(&current->mm->mmap_sem);
return ret;
}
@@ -254,7 +250,6 @@
int ret = -EINVAL;

down(&current->mm->mmap_sem);
- lock_kernel();
if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
goto out;

@@ -272,7 +267,6 @@

ret = do_mlockall(flags);
out:
- unlock_kernel();
up(&current->mm->mmap_sem);
return ret;
}
@@ -282,9 +276,7 @@
int ret;

down(&current->mm->mmap_sem);
- lock_kernel();
ret = do_mlockall(0);
- unlock_kernel();
up(&current->mm->mmap_sem);
return ret;
}
diff -urN linux-2.3.8/mm/mmap.c linux-bird.f_count/mm/mmap.c
--- linux-2.3.8/mm/mmap.c Mon Jun 21 13:50:10 1999
+++ linux-bird.f_count/mm/mmap.c Wed Jun 23 01:10:37 1999
@@ -77,10 +77,12 @@

if (file) {
if (vma->vm_flags & VM_DENYWRITE)
- file->f_dentry->d_inode->i_writecount++;
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
+ spin_lock(&file->f_dentry->d_inode->i_shared_lock);
if(vma->vm_next_share)
vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
*vma->vm_pprev_share = vma->vm_next_share;
+ spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
}
}

@@ -294,7 +296,12 @@
if (file) {
int correct_wcount = 0;
if (vma->vm_flags & VM_DENYWRITE) {
- if (file->f_dentry->d_inode->i_writecount > 0) {
+ /*
+ * WARNING: when we will take it out of the big lock
+ * we will need a spinlock here. See comments in
+ * fs/namei.c::get_write_access()
+ */
+ if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) {
error = -ETXTBSY;
goto free_vma;
}
@@ -303,17 +310,17 @@
* might). In any case, this takes care of any
* race that this might cause.
*/
- file->f_dentry->d_inode->i_writecount--;
+ atomic_dec(&file->f_dentry->d_inode->i_writecount);
correct_wcount = 1;
}
error = file->f_op->mmap(file, vma);
/* Fix up the count if necessary, then check for an error */
if (correct_wcount)
- file->f_dentry->d_inode->i_writecount++;
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
if (error)
goto unmap_and_free_vma;
+ get_file(file);
vma->vm_file = file;
- file->f_count++;
}

/*
@@ -547,7 +554,7 @@
mpnt->vm_file = area->vm_file;
mpnt->vm_pte = area->vm_pte;
if (mpnt->vm_file)
- mpnt->vm_file->f_count++;
+ get_file(mpnt->vm_file);
if (mpnt->vm_ops && mpnt->vm_ops->open)
mpnt->vm_ops->open(mpnt);
area->vm_end = addr; /* Truncate area */
@@ -875,13 +882,14 @@
if (file) {
struct inode * inode = file->f_dentry->d_inode;
if (vmp->vm_flags & VM_DENYWRITE)
- inode->i_writecount--;
-
+ atomic_dec(&inode->i_writecount);
+ spin_lock(&inode->i_shared_lock);
/* insert vmp into inode's share list */
if((vmp->vm_next_share = inode->i_mmap) != NULL)
inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
inode->i_mmap = vmp;
vmp->vm_pprev_share = &inode->i_mmap;
+ spin_unlock(&inode->i_shared_lock);
}
}

@@ -948,7 +956,7 @@
mm->map_count--;
remove_shared_vm_struct(mpnt);
if (mpnt->vm_file)
- fput(mpnt->vm_file);
+ fput(mpnt->vm_file); /* This one is safe */
kmem_cache_free(vm_area_cachep, mpnt);
mpnt = prev;
}
diff -urN linux-2.3.8/mm/mprotect.c linux-bird.f_count/mm/mprotect.c
--- linux-2.3.8/mm/mprotect.c Mon Jun 21 12:37:03 1999
+++ linux-bird.f_count/mm/mprotect.c Wed Jun 23 01:10:48 1999
@@ -103,7 +103,7 @@
n->vm_flags = newflags;
n->vm_page_prot = prot;
if (n->vm_file)
- n->vm_file->f_count++;
+ get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
insert_vm_struct(current->mm, n);
@@ -126,7 +126,7 @@
n->vm_flags = newflags;
n->vm_page_prot = prot;
if (n->vm_file)
- n->vm_file->f_count++;
+ get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
insert_vm_struct(current->mm, n);
@@ -158,7 +158,7 @@
vma->vm_flags = newflags;
vma->vm_page_prot = prot;
if (vma->vm_file)
- vma->vm_file->f_count += 2;
+ triple_file(vma->vm_file);
if (vma->vm_ops && vma->vm_ops->open) {
vma->vm_ops->open(left);
vma->vm_ops->open(right);
@@ -212,7 +212,6 @@
return 0;

down(&current->mm->mmap_sem);
- lock_kernel();

vma = find_vma(current->mm, start);
error = -EFAULT;
@@ -249,7 +248,6 @@
}
merge_segments(current->mm, start, end);
out:
- unlock_kernel();
up(&current->mm->mmap_sem);
return error;
}
diff -urN linux-2.3.8/mm/mremap.c linux-bird.f_count/mm/mremap.c
--- linux-2.3.8/mm/mremap.c Mon Jun 21 13:36:06 1999
+++ linux-bird.f_count/mm/mremap.c Wed Jun 23 01:10:52 1999
@@ -134,14 +134,12 @@
new_vma->vm_start = new_addr;
new_vma->vm_end = new_addr+new_len;
new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
- lock_kernel();
if (new_vma->vm_file)
- new_vma->vm_file->f_count++;
+ get_file(new_vma->vm_file);
if (new_vma->vm_ops && new_vma->vm_ops->open)
new_vma->vm_ops->open(new_vma);
insert_vm_struct(current->mm, new_vma);
merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
- unlock_kernel();
do_munmap(addr, old_len);
current->mm->total_vm += new_len >> PAGE_SHIFT;
if (new_vma->vm_flags & VM_LOCKED) {
diff -urN linux-2.3.8/net/core/scm.c linux-bird.f_count/net/core/scm.c
--- linux-2.3.8/net/core/scm.c Mon Jun 21 12:37:05 1999
+++ linux-bird.f_count/net/core/scm.c Wed Jun 23 01:11:04 1999
@@ -232,8 +232,8 @@
break;
}
/* Bump the usage count and install the file. */
- fp[i]->f_count++;
- current->files->fd[new_fd] = fp[i];
+ get_file(fp[i]);
+ fd_install(new_fd, fp[i]);
}

if (i > 0)
@@ -271,10 +271,9 @@

new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL);
if (new_fpl) {
- memcpy(new_fpl, fpl, sizeof(*fpl));
-
for (i=fpl->count-1; i>=0; i--)
- fpl->fp[i]->f_count++;
+ get_file(fpl->fp[i]);
+ memcpy(new_fpl, fpl, sizeof(*fpl));
}
return new_fpl;
}
diff -urN linux-2.3.8/net/socket.c linux-bird.f_count/net/socket.c
--- linux-2.3.8/net/socket.c Mon Jun 21 13:40:46 1999
+++ linux-bird.f_count/net/socket.c Tue Jun 22 23:12:08 1999
@@ -187,9 +187,10 @@
* Obtains the first available file descriptor and sets it up for use.
*/

-static int get_fd(struct inode *inode)
+static int get_fd(struct socket *sock)
{
int fd;
+ struct inode *inode = sock->inode;

/*
* Find a file descriptor suitable for return to the user.
@@ -217,11 +218,14 @@
*/
inode->i_count++;

- fd_install(fd, file);
file->f_op = &socket_file_ops;
file->f_mode = 3;
file->f_flags = O_RDWR;
file->f_pos = 0;
+ if (sock->ops->bind_file)
+ sock->ops->bind_file(sock, file);
+ fd_install(fd, file);
+ sock->file = file;
}
return fd;
}
@@ -653,11 +657,9 @@
if (retval < 0)
goto out;

- retval = get_fd(sock->inode);
+ retval = get_fd(sock);
if (retval < 0)
goto out_release;
- sock->file = fcheck(retval);
-
out:
unlock_kernel();
return retval;
@@ -822,9 +824,8 @@
goto out_release;
newsock = socki_lookup(inode);

- if ((err = get_fd(inode)) < 0)
+ if ((err = get_fd(newsock)) < 0)
goto out_release;
- newsock->file = fcheck(err);

if (upeer_sockaddr)
{
diff -urN linux-2.3.8/net/sunrpc/xprt.c linux-bird.f_count/net/sunrpc/xprt.c
--- linux-2.3.8/net/sunrpc/xprt.c Mon Jun 21 13:41:07 1999
+++ linux-bird.f_count/net/sunrpc/xprt.c Wed Jun 23 01:11:10 1999
@@ -1455,8 +1455,8 @@

proto = (sock->type == SOCK_DGRAM)? IPPROTO_UDP : IPPROTO_TCP;
if ((xprt = xprt_setup(sock, proto, ap, to)) != NULL) {
+ get_file(file);
xprt->file = file;
- file->f_count++;
}

return xprt;
diff -urN linux-2.3.8/net/unix/af_unix.c linux-bird.f_count/net/unix/af_unix.c
--- linux-2.3.8/net/unix/af_unix.c Mon Jun 21 13:18:23 1999
+++ linux-bird.f_count/net/unix/af_unix.c Tue Jun 22 23:12:08 1999
@@ -112,6 +112,7 @@
int sysctl_unix_destroy_delay = 10*HZ;
int sysctl_unix_max_dgram_qlen = 10;

+struct file_list AF_UNIX_files = { NULL, SPIN_LOCK_UNLOCKED };
unix_socket *unix_socket_table[UNIX_HASH_SIZE+1];
static atomic_t unix_nr_socks = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(unix_ack_wqueue);
@@ -1015,7 +1016,7 @@
while (skb_queue_len(&other->receive_queue) >=
sysctl_unix_max_dgram_qlen)
{
- if (sock->file->f_flags & O_NONBLOCK)
+ if (msg->msg_flags & MSG_DONTWAIT)
{
err = -EAGAIN;
goto out_unlock;
@@ -1496,6 +1497,12 @@
sock_wake_async(sk->socket, 2);
}

+static void unix_bind_file(struct socket *sock, struct file *file)
+{
+ *(int*)&file->private_data = 0;
+ file_move(file, &AF_UNIX_files);
+}
+
#ifdef CONFIG_PROC_FS
static int unix_read_proc(char *buffer, char **start, off_t offset,
int length, int *eof, void *data)
@@ -1574,7 +1581,8 @@
sock_no_getsockopt,
sock_no_fcntl,
unix_stream_sendmsg,
- unix_stream_recvmsg
+ unix_stream_recvmsg,
+ unix_bind_file
};

struct proto_ops unix_dgram_ops = {
@@ -1595,7 +1603,8 @@
sock_no_getsockopt,
sock_no_fcntl,
unix_dgram_sendmsg,
- unix_dgram_recvmsg
+ unix_dgram_recvmsg,
+ unix_bind_file
};

struct net_proto_family unix_family_ops = {
diff -urN linux-2.3.8/net/unix/garbage.c linux-bird.f_count/net/unix/garbage.c
--- linux-2.3.8/net/unix/garbage.c Mon Jun 21 12:37:10 1999
+++ linux-bird.f_count/net/unix/garbage.c Wed Jun 23 00:09:47 1999
@@ -115,16 +115,14 @@

void unix_inflight(struct file *fp)
{
- unix_socket *s=unix_get_socket(fp);
- if(s)
- s->protinfo.af_unix.inflight++;
+ if (fp->f_list == &AF_UNIX_files)
+ (*(int*)&fp->private_data)--;
}

void unix_notinflight(struct file *fp)
{
- unix_socket *s=unix_get_socket(fp);
- if(s)
- s->protinfo.af_unix.inflight--;
+ if (fp->f_list == &AF_UNIX_files)
+ (*(int*)&fp->private_data)--;
}


@@ -162,6 +160,7 @@
unix_socket *s;
struct sk_buff_head hitlist;
struct sk_buff *skb;
+ struct file *fp;

/*
* Avoid a recursive GC.
@@ -192,16 +191,15 @@
* Push root set
*/

- forall_unix_sockets(i, s)
- {
- /*
- * If all instances of the descriptor are not
- * in flight we are in use.
- */
- if(s->socket && s->socket->file &&
- s->socket->file->f_count > s->protinfo.af_unix.inflight)
- maybe_unmark_and_push(s);
+ spin_lock(&AF_UNIX_files.fl_lock);
+ for(fp=AF_UNIX_files.fl_list; fp; fp=fp->f_next) {
+ if (!fp->f_dentry)
+ continue;
+ if ((int)fp->private_data >= file_count(fp))
+ continue;
+ maybe_unmark_and_push(fp->f_dentry->d_inode->u.socket_i.sk);
}
+ spin_unlock(&AF_UNIX_files.fl_lock);

/*
* Mark phase
\
 
 \ /
  Last update: 2005-03-22 13:52    [W:0.535 / U:0.132 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site