/*
       *  linux/fs/file_table.c
       *
       *  Copyright (C) 1991, 1992  Linus Torvalds
       *  Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
       */
      
      #include <linux/string.h>
      #include <linux/slab.h>
      #include <linux/file.h>
      #include <linux/init.h>
      #include <linux/module.h>
      #include <linux/smp_lock.h>
      
      /* sysctl tunables... */
      struct files_stat_struct files_stat = {0, 0, NR_FILE};
      
      /* Here the new files go */
      static LIST_HEAD(anon_list);
      /* And here the free ones sit */
      static LIST_HEAD(free_list);
      /* public *and* exported. Not pretty! */
      spinlock_t files_lock = SPIN_LOCK_UNLOCKED;
      
      /* 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.
       */
  31  struct file * get_empty_filp(void)
      {
      	static int old_max = 0;
      	struct file * f;
      
      	file_list_lock();
  37  	if (files_stat.nr_free_files > NR_RESERVED_FILES) {
      	used_one:
      		f = list_entry(free_list.next, struct file, f_list);
      		list_del(&f->f_list);
      		files_stat.nr_free_files--;
      	new_one:
      		memset(f, 0, sizeof(*f));
      		atomic_set(&f->f_count,1);
      		f->f_version = ++event;
      		f->f_uid = current->fsuid;
      		f->f_gid = current->fsgid;
      		list_add(&f->f_list, &anon_list);
  49  		file_list_unlock();
  50  		return f;
      	}
      	/*
      	 * Use a reserved one if we're the superuser
      	 */
  55  	if (files_stat.nr_free_files && !current->euid)
  56  		goto used_one;
      	/*
      	 * Allocate a new one if we're below the limit.
      	 */
  60  	if (files_stat.nr_files < files_stat.max_files) {
  61  		file_list_unlock();
      		f = kmem_cache_alloc(filp_cachep, SLAB_KERNEL);
      		file_list_lock();
  64  		if (f) {
      			files_stat.nr_files++;
  66  			goto new_one;
      		}
      		/* Big problems... */
      		printk("VFS: filp allocation failed\n");
      
  71  	} else if (files_stat.max_files > old_max) {
      		printk("VFS: file-max limit %d reached\n", files_stat.max_files);
      		old_max = files_stat.max_files;
      	}
  75  	file_list_unlock();
  76  	return NULL;
      }
      
      /*
       * Clear and initialize a (private) struct file for the given dentry,
       * and call the open function (if any).  The caller must verify that
       * inode->i_fop is not NULL.
       */
  84  int init_private_file(struct file *filp, struct dentry *dentry, int mode)
      {
      	memset(filp, 0, sizeof(*filp));
      	filp->f_mode   = mode;
      	atomic_set(&filp->f_count, 1);
      	filp->f_dentry = dentry;
      	filp->f_uid    = current->fsuid;
      	filp->f_gid    = current->fsgid;
      	filp->f_op     = dentry->d_inode->i_fop;
  93  	if (filp->f_op->open)
  94  		return filp->f_op->open(dentry->d_inode, filp);
  95  	else
  96  		return 0;
      }
      
  99  void fput(struct file * file)
      {
      	struct dentry * dentry = file->f_dentry;
      	struct vfsmount * mnt = file->f_vfsmnt;
      	struct inode * inode = dentry->d_inode;
      
 105  	if (atomic_dec_and_test(&file->f_count)) {
      		locks_remove_flock(file);
 107  		if (file->f_op && file->f_op->release)
      			file->f_op->release(inode, file);
 109  		fops_put(file->f_op);
      		file->f_dentry = NULL;
      		file->f_vfsmnt = NULL;
 112  		if (file->f_mode & FMODE_WRITE)
      			put_write_access(inode);
      		dput(dentry);
 115  		if (mnt)
      			mntput(mnt);
      		file_list_lock();
      		list_del(&file->f_list);
      		list_add(&file->f_list, &free_list);
      		files_stat.nr_free_files++;
 121  		file_list_unlock();
      	}
      }
      
 125  struct file * fget(unsigned int fd)
      {
      	struct file * file;
      	struct files_struct *files = current->files;
      
      	read_lock(&files->file_lock);
      	file = fcheck(fd);
 132  	if (file)
      		get_file(file);
 134  	read_unlock(&files->file_lock);
 135  	return file;
      }
      
      /* Here. put_filp() is SMP-safe now. */
      
 140  void put_filp(struct file *file)
      {
 142  	if(atomic_dec_and_test(&file->f_count)) {
      		file_list_lock();
      		list_del(&file->f_list);
      		list_add(&file->f_list, &free_list);
      		files_stat.nr_free_files++;
 147  		file_list_unlock();
      	}
      }
      
 151  void file_move(struct file *file, struct list_head *list)
      {
 153  	if (!list)
 154  		return;
      	file_list_lock();
      	list_del(&file->f_list);
      	list_add(&file->f_list, list);
 158  	file_list_unlock();
      }
      
 161  void file_moveto(struct file *new, struct file *old)
      {
      	file_list_lock();
      	list_del(&new->f_list);
      	list_add(&new->f_list, &old->f_list);
 166  	file_list_unlock();
      }
      
 169  int fs_may_remount_ro(struct super_block *sb)
      {
      	struct list_head *p;
      
      	/* Check that no files are currently opened for writing. */
      	file_list_lock();
 175  	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
      		struct file *file = list_entry(p, struct file, f_list);
      		struct inode *inode;
      
 179  		if (!file->f_dentry)
 180  			continue;
      
      		inode = file->f_dentry->d_inode;
      
      		/* File with pending delete? */
 185  		if (inode->i_nlink == 0)
 186  			goto too_bad;
      
      		/* Writable file? */
 189  		if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
 190  			goto too_bad;
      	}
 192  	file_list_unlock();
 193  	return 1; /* Tis' cool bro. */
      too_bad:
 195  	file_list_unlock();
 196  	return 0;
      }