⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 locks.c

📁 elinux jffs初始版本 具体了解JFFS的文件系统!
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/fs/locks.c * *  Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls. *  Doug Evans (dje@spiff.uucp), August 07, 1992 * *  Deadlock detection added. *  FIXME: one thing isn't handled yet: *	- mandatory locks (requires lots of changes elsewhere) *  Kelly Carmichael (kelly@[142.24.8.65]), September 17, 1994. * *  Miscellaneous edits, and a total rewrite of posix_lock_file() code. *  Kai Petzke (wpp@marie.physik.tu-berlin.de), 1994 *   *  Converted file_lock_table to a linked list from an array, which eliminates *  the limits on how many active file locks are open. *  Chad Page (pageone@netcom.com), November 27, 1994 *  *  Removed dependency on file descriptors. dup()'ed file descriptors now *  get the same locks as the original file descriptors, and a close() on *  any file descriptor removes ALL the locks on the file for the current *  process. Since locks still depend on the process id, locks are inherited *  after an exec() but not after a fork(). This agrees with POSIX, and both *  BSD and SVR4 practice. *  Andy Walker (andy@lysaker.kvaerner.no), February 14, 1995 * *  Scrapped free list which is redundant now that we allocate locks *  dynamically with kmalloc()/kfree(). *  Andy Walker (andy@lysaker.kvaerner.no), February 21, 1995 * *  Implemented two lock personalities - FL_FLOCK and FL_POSIX. * *  FL_POSIX locks are created with calls to fcntl() and lockf() through the *  fcntl() system call. They have the semantics described above. * *  FL_FLOCK locks are created with calls to flock(), through the flock() *  system call, which is new. Old C libraries implement flock() via fcntl() *  and will continue to use the old, broken implementation. * *  FL_FLOCK locks follow the 4.4 BSD flock() semantics. They are associated *  with a file pointer (filp). As a result they can be shared by a parent *  process and its children after a fork(). They are removed when the last *  file descriptor referring to the file pointer is closed (unless explicitly *  unlocked).  * *  FL_FLOCK locks never deadlock, an existing lock is always removed before *  upgrading from shared to exclusive (or vice versa). When this happens *  any processes blocked by the current lock are woken up and allowed to *  run before the new lock is applied. *  Andy Walker (andy@lysaker.kvaerner.no), June 09, 1995 * *  Removed some race conditions in flock_lock_file(), marked other possible *  races. Just grep for FIXME to see them.  *  Dmitry Gorodchanin (pgmdsg@ibi.com), February 09, 1996. * *  Addressed Dmitry's concerns. Deadlock checking no longer recursive. *  Lock allocation changed to GFP_ATOMIC as we can't afford to sleep *  once we've checked for blocking and deadlocking. *  Andy Walker (andy@lysaker.kvaerner.no), April 03, 1996. * *  Initial implementation of mandatory locks. SunOS turned out to be *  a rotten model, so I implemented the "obvious" semantics. *  See 'linux/Documentation/mandatory.txt' for details. *  Andy Walker (andy@lysaker.kvaerner.no), April 06, 1996. * *  Don't allow mandatory locks on mmap()'ed files. Added simple functions to *  check if a file has mandatory locks, used by mmap(), open() and creat() to *  see if system call should be rejected. Ref. HP-UX/SunOS/Solaris Reference *  Manual, Section 2. *  Andy Walker (andy@lysaker.kvaerner.no), April 09, 1996. * *  Tidied up block list handling. Added '/proc/locks' interface. *  Andy Walker (andy@lysaker.kvaerner.no), April 24, 1996. * *  Fixed deadlock condition for pathological code that mixes calls to *  flock() and fcntl(). *  Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996. * *  Allow only one type of locking scheme (FL_POSIX or FL_FLOCK) to be in use *  for a given file at a time. Changed the CONFIG_LOCK_MANDATORY scheme to *  guarantee sensible behaviour in the case where file system modules might *  be compiled with different options than the kernel itself. *  Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996. * *  Added a couple of missing wake_up() calls. Thanks to Thomas Meckel *  (Thomas.Meckel@mni.fh-giessen.de) for spotting this. *  Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996. * *  Changed FL_POSIX locks to use the block list in the same way as FL_FLOCK *  locks. Changed process synchronisation to avoid dereferencing locks that *  have already been freed. *  Andy Walker (andy@lysaker.kvaerner.no), Sep 21, 1996. * *  Made the block list a circular list to minimise searching in the list. *  Andy Walker (andy@lysaker.kvaerner.no), Sep 25, 1996. * *  Made mandatory locking a mount option. Default is not to allow mandatory *  locking. *  Andy Walker (andy@lysaker.kvaerner.no), Oct 04, 1996. * *  Fixed /proc/locks interface so that we can't overrun the buffer we are handed. *  Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997. */#include <linux/malloc.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <asm/segment.h>#define OFFSET_MAX	((off_t)0x7fffffff)	/* FIXME: move elsewhere? */static int flock_make_lock(struct file *filp, struct file_lock *fl,			       unsigned int cmd);static int posix_make_lock(struct file *filp, struct file_lock *fl,			       struct flock *l);static int flock_locks_conflict(struct file_lock *caller_fl,				struct file_lock *sys_fl);static int posix_locks_conflict(struct file_lock *caller_fl,				struct file_lock *sys_fl);static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);static int flock_lock_file(struct file *filp, struct file_lock *caller,			   unsigned int wait);static int posix_lock_file(struct file *filp, struct file_lock *caller,			   unsigned int wait);static int posix_locks_deadlock(struct task_struct *my_task,				struct task_struct *blocked_task);static void posix_remove_locks(struct file_lock **before, struct task_struct *task);static void flock_remove_locks(struct file_lock **before, struct file *filp);static struct file_lock *locks_empty_lock(void);static struct file_lock *locks_init_lock(struct file_lock *,					 struct file_lock *);static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait);static char *lock_get_status(struct file_lock *fl, int id, char *pfx);static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter);static void locks_delete_block(struct file_lock *blocker, struct file_lock *waiter);static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait);static struct file_lock *file_lock_table = NULL;/* Allocate a new lock, and initialize its fields from fl. * The lock is not inserted into any lists until locks_insert_lock() or  * locks_insert_block() are called. */static inline struct file_lock *locks_alloc_lock(struct file_lock *fl){	return locks_init_lock(locks_empty_lock(), fl);}/* Free lock not inserted in any queue. */static inline void locks_free_lock(struct file_lock *fl){	if (waitqueue_active(&fl->fl_wait))		panic("Aarggh: attempting to free lock with active wait queue - shoot Andy");	if (fl->fl_nextblock != NULL || fl->fl_prevblock != NULL)		panic("Aarggh: attempting to free lock with active block list - shoot Andy");			kfree(fl);	return;}/* Check if two locks overlap each other. */static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2){	return ((fl1->fl_end >= fl2->fl_start) &&		(fl2->fl_end >= fl1->fl_start));}/* Insert waiter into blocker's block list. * We use a circular list so that processes can be easily woken up in * the order they blocked. The documentation doesn't require this but * it seems seems like the reasonable thing to do. */static void locks_insert_block(struct file_lock *blocker, 			       struct file_lock *waiter){	struct file_lock *prevblock;	if (blocker->fl_prevblock == NULL)		/* No previous waiters - list is empty */		prevblock = blocker;	else		/* Previous waiters exist - add to end of list */		prevblock = blocker->fl_prevblock;	prevblock->fl_nextblock = waiter;	blocker->fl_prevblock = waiter;	waiter->fl_nextblock = blocker;	waiter->fl_prevblock = prevblock;		return;}/* Remove waiter from blocker's block list. * When blocker ends up pointing to itself then the list is empty. */static void locks_delete_block(struct file_lock *blocker,			       struct file_lock *waiter){	struct file_lock *nextblock;	struct file_lock *prevblock;		nextblock = waiter->fl_nextblock;	prevblock = waiter->fl_prevblock;	if (nextblock == NULL)		return;		nextblock->fl_prevblock = prevblock;	prevblock->fl_nextblock = nextblock;	waiter->fl_prevblock = waiter->fl_nextblock = NULL;	if (blocker->fl_nextblock == blocker)		/* No more locks on blocker's blocked list */		blocker->fl_prevblock = blocker->fl_nextblock = NULL;	return;}/* Wake up processes blocked waiting for blocker. * If told to wait then schedule the processes until the block list * is empty, otherwise empty the block list ourselves. */static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait){	struct file_lock *waiter;	while ((waiter = blocker->fl_nextblock) != NULL) {		wake_up(&waiter->fl_wait);		if (wait)			/* Let the blocked process remove waiter from the			 * block list when it gets scheduled.			 */			schedule();		else			/* Remove waiter from the block list, because by the			 * time it wakes up blocker won't exist any more.			 */			locks_delete_block(blocker, waiter);	}	return;}/* flock() system call entry point. Apply a FL_FLOCK style lock to * an open file descriptor. */asmlinkage int sys_flock(unsigned int fd, unsigned int cmd){	struct file_lock file_lock;	struct file *filp;	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))		return (-EBADF);	if (!flock_make_lock(filp, &file_lock, cmd))		return (-EINVAL);		if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))		return (-EBADF);	return (flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1));}/* Report the first existing lock that would conflict with l. * This implements the F_GETLK command of fcntl(). */int fcntl_getlk(unsigned int fd, struct flock *l){	int error;	struct flock flock;	struct file *filp;	struct file_lock *fl,file_lock;	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))		return (-EBADF);	error = verify_area(VERIFY_WRITE, l, sizeof(*l));	if (error)		return (error);	memcpy_fromfs(&flock, l, sizeof(flock));	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))		return (-EINVAL);	if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))		return (-EINVAL);	flock.l_type = F_UNLCK;	for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {		if (!(fl->fl_flags & FL_POSIX))			break;		if (posix_locks_conflict(&file_lock, fl)) {			flock.l_pid = fl->fl_owner->pid;			flock.l_start = fl->fl_start;			flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :				fl->fl_end - fl->fl_start + 1;			flock.l_whence = 0;			flock.l_type = fl->fl_type;			break;		}	}	memcpy_tofs(l, &flock, sizeof(flock));	return (0);}/* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). * It also emulates flock() in a pretty broken way for older C * libraries. */int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l){	int error;	struct file *filp;	struct file_lock file_lock;	struct flock flock;	struct inode *inode;	/* Get arguments and validate them ...	 */	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))		return (-EBADF);		error = verify_area(VERIFY_READ, l, sizeof(*l));	if (error)		return (error);		if (!(inode = filp->f_inode))		return (-EINVAL);		/*	 * This might block, so we do it before checking the inode.	 */	memcpy_fromfs(&flock, l, sizeof(flock));	/* Don't allow mandatory locks on files that may be memory mapped	 * and shared.	 */#ifndef NO_MM	if (IS_MANDLOCK(inode) &&	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&	    inode->i_mmap) {		struct vm_area_struct *vma = inode->i_mmap;		do {			if (vma->vm_flags & VM_MAYSHARE)				return (-EAGAIN);			vma = vma->vm_next_share;		} while (vma != inode->i_mmap);	}#endif	if (!posix_make_lock(filp, &file_lock, &flock))		return (-EINVAL);		switch (flock.l_type) {	case F_RDLCK:		if (!(filp->f_mode & 1))			return (-EBADF);		break;	case F_WRLCK:		if (!(filp->f_mode & 2))			return (-EBADF);		break;	case F_UNLCK:		break;	case F_SHLCK:	case F_EXLCK:#if 1/* warn a bit for now, but don't overdo it */{	static int count = 0;	if (!count) {		count=1;		printk(KERN_WARNING		       "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n",		       current->pid, current->comm);	}}#endif		if (!(filp->f_mode & 3))			return (-EBADF);		break;	default:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -