Messages in this thread Patch in this message | | | Date | Tue, 22 Jun 1999 14:53:50 -0400 (EDT) | From | Alexander Viro <> | Subject | Extended f_count patch (SMP-safe handling of struct file) |
| |
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. diff -urN linux-2.3.8-pre2/arch/alpha/kernel/osf_sys.c linux-bird.f_count/arch/alpha/kernel/osf_sys.c --- linux-2.3.8-pre2/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 14:24:30 1999 @@ -255,6 +255,7 @@ struct file *file = NULL; unsigned long ret = -EBADF; + down(¤t->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(¤t->mm->mmap_sem); return ret; } diff -urN linux-2.3.8-pre2/arch/arm/kernel/sys_arm.c linux-bird.f_count/arch/arm/kernel/sys_arm.c --- linux-2.3.8-pre2/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 14:24:31 1999 @@ -72,6 +72,7 @@ struct file * file = NULL; struct mmap_arg_struct a; + down(¤t->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(¤t->mm->mmap_sem); return error; } diff -urN linux-2.3.8-pre2/arch/mips/kernel/irixelf.c linux-bird.f_count/arch/mips/kernel/irixelf.c --- linux-2.3.8-pre2/arch/mips/kernel/irixelf.c Mon Jun 21 13:32:20 1999 +++ linux-bird.f_count/arch/mips/kernel/irixelf.c Tue Jun 22 14:24:31 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-pre2/arch/mips/kernel/syscall.c linux-bird.f_count/arch/mips/kernel/syscall.c --- linux-2.3.8-pre2/arch/mips/kernel/syscall.c Mon Jun 21 12:35:57 1999 +++ linux-bird.f_count/arch/mips/kernel/syscall.c Tue Jun 22 14:24:31 1999 @@ -61,6 +61,7 @@ struct file * file = NULL; unsigned long error = -EFAULT; + down(¤t->mm->mmap_sem); lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { error = -EBADF; @@ -74,6 +75,7 @@ fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return error; } diff -urN linux-2.3.8-pre2/arch/mips/kernel/sysirix.c linux-bird.f_count/arch/mips/kernel/sysirix.c --- linux-2.3.8-pre2/arch/mips/kernel/sysirix.c Mon Jun 21 13:32:21 1999 +++ linux-bird.f_count/arch/mips/kernel/sysirix.c Tue Jun 22 14:24:31 1999 @@ -1103,6 +1103,7 @@ struct file *file = NULL; unsigned long retval; + down(¤t->mm->mmap_sem); lock_kernel(); if(!(flags & MAP_ANONYMOUS)) { if(!(file = fget(fd))) { @@ -1130,6 +1131,7 @@ out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } diff -urN linux-2.3.8-pre2/arch/ppc/kernel/syscalls.c linux-bird.f_count/arch/ppc/kernel/syscalls.c --- linux-2.3.8-pre2/arch/ppc/kernel/syscalls.c Mon Jun 21 13:32:31 1999 +++ linux-bird.f_count/arch/ppc/kernel/syscalls.c Tue Jun 22 14:24:31 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(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, offset); + up(¤t->mm->mmap_sem); + if (file) + fput(file); out: unlock_kernel(); return ret; diff -urN linux-2.3.8-pre2/arch/sparc/kernel/sunos_ioctl.c linux-bird.f_count/arch/sparc/kernel/sunos_ioctl.c --- linux-2.3.8-pre2/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 14:24:31 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-pre2/arch/sparc/mm/srmmu.c linux-bird.f_count/arch/sparc/mm/srmmu.c --- linux-2.3.8-pre2/arch/sparc/mm/srmmu.c Mon Jun 21 12:36:02 1999 +++ linux-bird.f_count/arch/sparc/mm/srmmu.c Tue Jun 22 14:24:31 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-pre2/arch/sparc/mm/sun4c.c linux-bird.f_count/arch/sparc/mm/sun4c.c --- linux-2.3.8-pre2/arch/sparc/mm/sun4c.c Mon Jun 21 12:36:02 1999 +++ linux-bird.f_count/arch/sparc/mm/sun4c.c Tue Jun 22 14:24:31 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-pre2/arch/sparc64/kernel/sys_sparc32.c linux-bird.f_count/arch/sparc64/kernel/sys_sparc32.c --- linux-2.3.8-pre2/arch/sparc64/kernel/sys_sparc32.c Mon Jun 21 13:42:00 1999 +++ linux-bird.f_count/arch/sparc64/kernel/sys_sparc32.c Tue Jun 22 14:24:31 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]; + atomic_inc(&fp[i]->f_count); + fd_install(new_fd, fp[i]); } if (i > 0) { diff -urN linux-2.3.8-pre2/arch/sparc64/kernel/sys_sunos32.c linux-bird.f_count/arch/sparc64/kernel/sys_sunos32.c --- linux-2.3.8-pre2/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 14:24:31 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-pre2/arch/sparc64/solaris/misc.c linux-bird.f_count/arch/sparc64/solaris/misc.c --- linux-2.3.8-pre2/arch/sparc64/solaris/misc.c Mon Jun 21 12:36:05 1999 +++ linux-bird.f_count/arch/sparc64/solaris/misc.c Tue Jun 22 14:24:31 1999 @@ -83,6 +83,7 @@ } } + down(¤t->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(¤t->mm->mmap_sem); if (file) fput(file); out: diff -urN linux-2.3.8-pre2/drivers/block/loop.c linux-bird.f_count/drivers/block/loop.c --- linux-2.3.8-pre2/drivers/block/loop.c Mon Jun 21 13:19:53 1999 +++ linux-bird.f_count/drivers/block/loop.c Tue Jun 22 14:24:31 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-pre2/drivers/char/sysrq.c linux-bird.f_count/drivers/char/sysrq.c --- linux-2.3.8-pre2/drivers/char/sysrq.c Mon Jun 21 12:36:12 1999 +++ linux-bird.f_count/drivers/char/sysrq.c Tue Jun 22 14:24:31 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 && atomic_read(&file->f_count) + && 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-pre2/drivers/char/tpqic02.c linux-bird.f_count/drivers/char/tpqic02.c --- linux-2.3.8-pre2/drivers/char/tpqic02.c Mon Jun 21 12:49:55 1999 +++ linux-bird.f_count/drivers/char/tpqic02.c Tue Jun 22 14:24:31 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 (atomic_read(&filp->f_count)>1) /* filp->f_count==1 for the first open() */ { return -EBUSY; } diff -urN linux-2.3.8-pre2/drivers/char/tty_io.c linux-bird.f_count/drivers/char/tty_io.c --- linux-2.3.8-pre2/drivers/char/tty_io.c Mon Jun 21 13:56:26 1999 +++ linux-bird.f_count/drivers/char/tty_io.c Tue Jun 22 14:24:31 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(file, &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); + init_spin_lock(&tty->tty_files.fl_lock); + tty->tty_files.fl_list = NULL; } /* diff -urN linux-2.3.8-pre2/drivers/scsi/st.c linux-bird.f_count/drivers/scsi/st.c --- linux-2.3.8-pre2/drivers/scsi/st.c Mon Jun 21 13:12:01 1999 +++ linux-bird.f_count/drivers/scsi/st.c Tue Jun 22 14:24:31 1999 @@ -890,7 +890,7 @@ kdev_t devt = inode->i_rdev; int dev; - if (filp->f_count > 1) + if (atomic_read(&filp->f_count) > 1) return 0; dev = TAPE_NR(devt); diff -urN linux-2.3.8-pre2/drivers/sgi/char/usema.c linux-bird.f_count/drivers/sgi/char/usema.c --- linux-2.3.8-pre2/drivers/sgi/char/usema.c Mon Jun 21 13:07:41 1999 +++ linux-bird.f_count/drivers/sgi/char/usema.c Tue Jun 22 14:24:31 1999 @@ -50,8 +50,8 @@ if (newfd < 0) return newfd; - current->files->fd [newfd] = usema->filp; - usema->filp->f_count++; + atomic_inc(&usema->filp->f_count); + fd_install(newfd, usema->filp); /* Is that it? */ printk("UIOCATTACHSEMA: new usema fd is %d", newfd); return newfd; diff -urN linux-2.3.8-pre2/fs/dquot.c linux-bird.f_count/fs/dquot.c --- linux-2.3.8-pre2/fs/dquot.c Mon Jun 21 12:55:30 1999 +++ linux-bird.f_count/fs/dquot.c Tue Jun 22 14:24:31 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-pre2/fs/exec.c linux-bird.f_count/fs/exec.c --- linux-2.3.8-pre2/fs/exec.c Mon Jun 21 13:30:15 1999 +++ linux-bird.f_count/fs/exec.c Tue Jun 22 14:24:31 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-pre2/fs/file_table.c linux-bird.f_count/fs/file_table.c --- linux-2.3.8-pre2/fs/file_table.c Mon Jun 21 13:30:15 1999 +++ linux-bird.f_count/fs/file_table.c Tue Jun 22 14:24:31 1999 @@ -20,25 +20,21 @@ /* 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 struct file *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 +63,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(file, anon_list, NULL); return f; } /* @@ -96,7 +96,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 +110,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 +123,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 +136,67 @@ void fput(struct file *file) { - int count = file->f_count-1; + if (atomic_dec_and_test(&file->f_count)) { + atomic_inc(&file->f_count); + + 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 lise_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) +{ + strcut 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-pre2/fs/hpfs/mmap.c linux-bird.f_count/fs/hpfs/mmap.c --- linux-2.3.8-pre2/fs/hpfs/mmap.c Mon Jun 21 13:03:49 1999 +++ linux-bird.f_count/fs/hpfs/mmap.c Tue Jun 22 14:24:31 1999 @@ -119,9 +119,9 @@ mark_inode_dirty(inode); }*/ - vma->vm_file = file; /*inode->i_count++;*/ - file->f_count++; + atomic_inc(&file->f_count); + vma->vm_file = file; vma->vm_ops = &hpfs_file_mmap; /*printk("end mmap\n");*/ return 0; diff -urN linux-2.3.8-pre2/fs/inode.c linux-bird.f_count/fs/inode.c --- linux-2.3.8-pre2/fs/inode.c Mon Jun 21 14:12:09 1999 +++ linux-bird.f_count/fs/inode.c Tue Jun 22 14:24:31 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-pre2/fs/locks.c linux-bird.f_count/fs/locks.c --- linux-2.3.8-pre2/fs/locks.c Tue Jun 22 09:06:09 1999 +++ linux-bird.f_count/fs/locks.c Tue Jun 22 14:24:31 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-pre2/fs/namei.c linux-bird.f_count/fs/namei.c --- linux-2.3.8-pre2/fs/namei.c Mon Jun 21 13:07:59 1999 +++ linux-bird.f_count/fs/namei.c Tue Jun 22 14:24:31 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-pre2/fs/nfs/write.c linux-bird.f_count/fs/nfs/write.c --- linux-2.3.8-pre2/fs/nfs/write.c Mon Jun 21 14:31:25 1999 +++ linux-bird.f_count/fs/nfs/write.c Tue Jun 22 14:24:31 1999 @@ -305,6 +305,7 @@ goto out_req; /* Put the task on inode's writeback request list. */ + atomic_inc(&file->f_count); 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-pre2/fs/nfsd/vfs.c linux-bird.f_count/fs/nfsd/vfs.c --- linux-2.3.8-pre2/fs/nfsd/vfs.c Mon Jun 21 13:08:12 1999 +++ linux-bird.f_count/fs/nfsd/vfs.c Tue Jun 22 14:24:31 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-pre2/fs/open.c linux-bird.f_count/fs/open.c --- linux-2.3.8-pre2/fs/open.c Mon Jun 21 13:12:23 1999 +++ linux-bird.f_count/fs/open.c Tue Jun 22 14:24:31 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 (atomic_read(&filp->f_count) == 0) { printk("VFS: Close: file count is 0\n"); return 0; } diff -urN linux-2.3.8-pre2/fs/proc/inode.c linux-bird.f_count/fs/proc/inode.c --- linux-2.3.8-pre2/fs/proc/inode.c Mon Jun 21 13:39:45 1999 +++ linux-bird.f_count/fs/proc/inode.c Tue Jun 22 14:24:32 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); + sb->generic_sbp = (void*) proc_super_blocks; + proc_super_blocks = sb; unlock_super(s); return s; diff -urN linux-2.3.8-pre2/fs/proc/root.c linux-bird.f_count/fs/proc/root.c --- linux-2.3.8-pre2/fs/proc/root.c Mon Jun 21 14:31:30 1999 +++ linux-bird.f_count/fs/proc/root.c Tue Jun 22 14:24:32 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-pre2/fs/select.c linux-bird.f_count/fs/select.c --- linux-2.3.8-pre2/fs/select.c Mon Jun 21 13:12:24 1999 +++ linux-bird.f_count/fs/select.c Tue Jun 22 14:24:32 1999 @@ -65,8 +65,8 @@ struct poll_table_entry * entry; ok_table: entry = p->entry + p->nr; + atomic_inc(&filp->f_count); 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-pre2/fs/super.c linux-bird.f_count/fs/super.c --- linux-2.3.8-pre2/fs/super.c Mon Jun 21 14:12:10 1999 +++ linux-bird.f_count/fs/super.c Tue Jun 22 14:24:32 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->files->fl_lock); + s->files->fl_list = NULL; } return s; } diff -urN linux-2.3.8-pre2/include/linux/file.h linux-bird.f_count/include/linux/file.h --- linux-2.3.8-pre2/include/linux/file.h Mon Jun 21 13:40:25 1999 +++ linux-bird.f_count/include/linux/file.h Tue Jun 22 14:24:32 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++; + atomic_inc(&file->f_count); return file; } diff -urN linux-2.3.8-pre2/include/linux/fs.h linux-bird.f_count/include/linux/fs.h --- linux-2.3.8-pre2/include/linux/fs.h Mon Jun 21 14:36:57 1999 +++ linux-bird.f_count/include/linux/fs.h Tue Jun 22 14:24:32 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); +} -#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_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); +} + +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,6 +433,7 @@ /* needed for tty driver, and maybe others */ void *private_data; + struct file_list *f_list; /* pointer back to the list */ }; extern int init_private_file(struct file *, struct dentry *, int); @@ -481,6 +501,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 +547,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; @@ -731,8 +757,6 @@ extern struct file_operations write_pipe_fops; extern struct file_operations rdwr_pipe_fops; -extern struct file_system_type *get_fs_type(const char *); - extern int fs_may_remount_ro(struct super_block *); extern int fs_may_mount(kdev_t); @@ -846,6 +870,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-pre2/include/linux/proc_fs.h linux-bird.f_count/include/linux/proc_fs.h --- linux-2.3.8-pre2/include/linux/proc_fs.h Mon Jun 21 14:27:29 1999 +++ linux-bird.f_count/include/linux/proc_fs.h Tue Jun 22 14:24:32 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-pre2/include/linux/tty.h linux-bird.f_count/include/linux/tty.h --- linux-2.3.8-pre2/include/linux/tty.h Mon Jun 21 12:40:29 1999 +++ linux-bird.f_count/include/linux/tty.h Tue Jun 22 14:24:32 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-pre2/ipc/shm.c linux-bird.f_count/ipc/shm.c --- linux-2.3.8-pre2/ipc/shm.c Mon Jun 21 13:50:07 1999 +++ linux-bird.f_count/ipc/shm.c Tue Jun 22 14:24:32 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-pre2/kernel/acct.c linux-bird.f_count/kernel/acct.c --- linux-2.3.8-pre2/kernel/acct.c Mon Jun 21 14:18:12 1999 +++ linux-bird.f_count/kernel/acct.c Tue Jun 22 14:24:32 1999 @@ -276,7 +276,7 @@ */ if (!file) return 0; - file->f_count++; + atomic_inc(&file->f_count); if (!check_free_space(file)) { fput(file); return 0; diff -urN linux-2.3.8-pre2/kernel/exit.c linux-bird.f_count/kernel/exit.c --- linux-2.3.8-pre2/kernel/exit.c Mon Jun 21 12:40:36 1999 +++ linux-bird.f_count/kernel/exit.c Tue Jun 22 14:24:32 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-pre2/kernel/fork.c linux-bird.f_count/kernel/fork.c --- linux-2.3.8-pre2/kernel/fork.c Mon Jun 21 13:18:00 1999 +++ linux-bird.f_count/kernel/fork.c Tue Jun 22 14:24:32 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++; + atomic_inc(&file->f_count); 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++; + atomic_inc(&f->f_count); + *new_fds = f; new_fds++; } /* This is long word aligned thus could use a optimized version */ diff -urN linux-2.3.8-pre2/mm/filemap.c linux-bird.f_count/mm/filemap.c --- linux-2.3.8-pre2/mm/filemap.c Tue Jun 22 09:06:09 1999 +++ linux-bird.f_count/mm/filemap.c Tue Jun 22 14:26:04 1999 @@ -1473,7 +1473,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++; + atomic_inc(&file->f_count); result = do_write_page(inode, file, (const char *) page, offset); fput(file); return result; diff -urN linux-2.3.8-pre2/mm/memory.c linux-bird.f_count/mm/memory.c --- linux-2.3.8-pre2/mm/memory.c Mon Jun 21 13:50:10 1999 +++ linux-bird.f_count/mm/memory.c Tue Jun 22 14:24:32 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-pre2/mm/mlock.c linux-bird.f_count/mm/mlock.c --- linux-2.3.8-pre2/mm/mlock.c Mon Jun 21 13:09:09 1999 +++ linux-bird.f_count/mm/mlock.c Tue Jun 22 14:24:32 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++; + atomic_inc(&n->vm_file->f_count); 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++; + atomic_inc(&n->vm_file->f_count); 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; + atomic_add(2, &vma->vm_file->f_count); if (vma->vm_ops && vma->vm_ops->open) { vma->vm_ops->open(left); @@ -179,7 +179,6 @@ int error = -ENOMEM; down(¤t->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(¤t->mm->mmap_sem); return error; } @@ -210,11 +208,9 @@ int ret; down(¤t->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(¤t->mm->mmap_sem); return ret; } @@ -254,7 +250,6 @@ int ret = -EINVAL; down(¤t->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(¤t->mm->mmap_sem); return ret; } @@ -282,9 +276,7 @@ int ret; down(¤t->mm->mmap_sem); - lock_kernel(); ret = do_mlockall(0); - unlock_kernel(); up(¤t->mm->mmap_sem); return ret; } diff -urN linux-2.3.8-pre2/mm/mmap.c linux-bird.f_count/mm/mmap.c --- linux-2.3.8-pre2/mm/mmap.c Mon Jun 21 13:50:10 1999 +++ linux-bird.f_count/mm/mmap.c Tue Jun 22 14:24:32 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; + atomic_inc(&file->f_count); 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++; + atomic_inc(&mpnt->vm_file->f_count); 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-pre2/mm/mprotect.c linux-bird.f_count/mm/mprotect.c --- linux-2.3.8-pre2/mm/mprotect.c Mon Jun 21 12:37:03 1999 +++ linux-bird.f_count/mm/mprotect.c Tue Jun 22 14:24:32 1999 @@ -103,7 +103,7 @@ n->vm_flags = newflags; n->vm_page_prot = prot; if (n->vm_file) - n->vm_file->f_count++; + atomic_inc(&n->vm_file->f_count); 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++; + atomic_inc(&n->vm_file->f_count); 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; + atomic_add(2,&vma->vm_file->f_count); 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(¤t->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(¤t->mm->mmap_sem); return error; } diff -urN linux-2.3.8-pre2/mm/mremap.c linux-bird.f_count/mm/mremap.c --- linux-2.3.8-pre2/mm/mremap.c Mon Jun 21 13:36:06 1999 +++ linux-bird.f_count/mm/mremap.c Tue Jun 22 14:24:32 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++; + atomic_inc(&new_vma->vm_file->f_count); 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-pre2/net/core/scm.c linux-bird.f_count/net/core/scm.c --- linux-2.3.8-pre2/net/core/scm.c Mon Jun 21 12:37:05 1999 +++ linux-bird.f_count/net/core/scm.c Tue Jun 22 14:24:32 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]; + atomic_inc(&fp[i]->f_count); + 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++; + atomic_inc(&fpl->fp[i]->f_count); + memcpy(new_fpl, fpl, sizeof(*fpl)); } return new_fpl; } diff -urN linux-2.3.8-pre2/net/socket.c linux-bird.f_count/net/socket.c --- linux-2.3.8-pre2/net/socket.c Mon Jun 21 13:40:46 1999 +++ linux-bird.f_count/net/socket.c Tue Jun 22 14:24:32 1999 @@ -217,11 +217,11 @@ */ 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; + fd_install(fd, file); } return fd; } diff -urN linux-2.3.8-pre2/net/sunrpc/xprt.c linux-bird.f_count/net/sunrpc/xprt.c --- linux-2.3.8-pre2/net/sunrpc/xprt.c Mon Jun 21 13:41:07 1999 +++ linux-bird.f_count/net/sunrpc/xprt.c Tue Jun 22 14:24:32 1999 @@ -1455,8 +1455,8 @@ proto = (sock->type == SOCK_DGRAM)? IPPROTO_UDP : IPPROTO_TCP; if ((xprt = xprt_setup(sock, proto, ap, to)) != NULL) { + atomic_inc(&file->f_count); xprt->file = file; - file->f_count++; } return xprt; diff -urN linux-2.3.8-pre2/net/unix/garbage.c linux-bird.f_count/net/unix/garbage.c --- linux-2.3.8-pre2/net/unix/garbage.c Mon Jun 21 12:37:10 1999 +++ linux-bird.f_count/net/unix/garbage.c Tue Jun 22 14:24:32 1999 @@ -199,7 +199,8 @@ * in flight we are in use. */ if(s->socket && s->socket->file && - s->socket->file->f_count > s->protinfo.af_unix.inflight) + atomic_read(&s->socket->file->f_count) > + s->protinfo.af_unix.inflight) maybe_unmark_and_push(s); } | |