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

📄 locks.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
					locks_delete_lock(before, 0);					continue;				}				/* Replace the old lock with the new one.				 * Wake up anybody waiting for the old one,				 * as the change in lock type might satisfy				 * their needs.				 */				locks_wake_up_blocks(fl, 0);	/* This cannot schedule()! */				fl->fl_start = caller->fl_start;				fl->fl_end = caller->fl_end;				fl->fl_type = caller->fl_type;				fl->fl_u = caller->fl_u;				caller = fl;				added = 1;			}		}		/* Go on to next lock.		 */	next_lock:		before = &fl->fl_next;	}	error = 0;	if (!added) {		if (caller->fl_type == F_UNLCK)			goto out;		locks_copy_lock(new_fl, caller);		locks_insert_lock(before, new_fl);		new_fl = NULL;	}	if (right) {		if (left == right) {			/* The new lock breaks the old one in two pieces,			 * so we have to use the second new lock.			 */			left = new_fl2;			new_fl2 = NULL;			locks_copy_lock(left, right);			locks_insert_lock(before, left);		}		right->fl_start = caller->fl_end + 1;		locks_wake_up_blocks(right, 0);	}	if (left) {		left->fl_end = caller->fl_start - 1;		locks_wake_up_blocks(left, 0);	}out:	unlock_kernel();out_nolock:	/*	 * Free any unused locks.	 */	if (new_fl)		locks_free_lock(new_fl);	if (new_fl2)		locks_free_lock(new_fl2);	return error;}static inline int flock_translate_cmd(int cmd) {#ifdef MSNFS	if (cmd & LOCK_MAND)		return cmd & (LOCK_MAND | LOCK_RW);#endif	switch (cmd &~ LOCK_NB) {	case LOCK_SH:		return F_RDLCK;	case LOCK_EX:		return F_WRLCK;	case LOCK_UN:		return F_UNLCK;	}	return -EINVAL;}/** *	__get_lease	-	revoke all outstanding leases on file *	@inode: the inode of the file to return *	@mode: the open mode (read or write) * *	get_lease (inlined for speed) has checked there already *	is a lease on this file.  Leases are broken on a call to open() *	or truncate().  This function can sleep unless you *	specified %O_NONBLOCK to your open(). */int __get_lease(struct inode *inode, unsigned int mode){	int error = 0, future;	struct file_lock *new_fl, *flock;	struct file_lock *fl;	int alloc_err;	alloc_err = lease_alloc(NULL, 0, &new_fl);	lock_kernel();	flock = inode->i_flock;	if (flock->fl_type & F_INPROGRESS) {		if ((mode & O_NONBLOCK)		    || (flock->fl_owner == current->files)) {			error = -EWOULDBLOCK;			goto out;		}		if (alloc_err != 0) {			error = alloc_err;			goto out;		}		do {			error = locks_block_on(flock, new_fl);			if (error != 0)				goto out;			flock = inode->i_flock;			if (!(flock && (flock->fl_flags & FL_LEASE)))				goto out;		} while (flock->fl_type & F_INPROGRESS);	}	if (mode & FMODE_WRITE) {		/* If we want write access, we have to revoke any lease. */		future = F_UNLCK | F_INPROGRESS;	} else if (flock->fl_type & F_WRLCK) {		/* Downgrade the exclusive lease to a read-only lease. */		future = F_RDLCK | F_INPROGRESS;	} else {		/* the existing lease was read-only, so we can read too. */		goto out;	}	if (alloc_err && (flock->fl_owner != current->files)) {		error = alloc_err;		goto out;	}	fl = flock;	do {		fl->fl_type = future;		fl = fl->fl_next;	} while (fl != NULL && (fl->fl_flags & FL_LEASE));	kill_fasync(&flock->fl_fasync, SIGIO, POLL_MSG);	if ((mode & O_NONBLOCK) || (flock->fl_owner == current->files)) {		error = -EWOULDBLOCK;		goto out;	}	if (lease_break_time > 0)		error = lease_break_time * HZ;	else		error = 0;restart:	error = locks_block_on_timeout(flock, new_fl, error);	if (error == 0) {		/* We timed out.  Unilaterally break the lease. */		locks_delete_lock(&inode->i_flock, 0);		printk(KERN_WARNING "lease timed out\n");	} else if (error > 0) {		flock = inode->i_flock;		if (flock && (flock->fl_flags & FL_LEASE))			goto restart;		error = 0;	}out:	unlock_kernel();	if (!alloc_err)		locks_free_lock(new_fl);	return error;}/** *	lease_get_mtime *	@inode: the inode * * This is to force NFS clients to flush their caches for files with * exclusive leases.  The justification is that if someone has an * exclusive lease, then they could be modifiying it. */time_t lease_get_mtime(struct inode *inode){	struct file_lock *flock = inode->i_flock;	if (flock && (flock->fl_flags & FL_LEASE) && (flock->fl_type & F_WRLCK))		return CURRENT_TIME;	return inode->i_mtime;}/** *	fcntl_getlease - Enquire what lease is currently active *	@filp: the file * *	The value returned by this function will be one of * *	%F_RDLCK to indicate a read-only (type II) lease is held. * *	%F_WRLCK to indicate an exclusive lease is held. * *	XXX: sfr & i disagree over whether F_INPROGRESS *	should be returned to userspace. */int fcntl_getlease(struct file *filp){	struct file_lock *fl;		fl = filp->f_dentry->d_inode->i_flock;	if ((fl == NULL) || ((fl->fl_flags & FL_LEASE) == 0))		return F_UNLCK;	return fl->fl_type & ~F_INPROGRESS;}/* We already had a lease on this file; just change its type */static int lease_modify(struct file_lock **before, int arg, int fd, struct file *filp){	struct file_lock *fl = *before;	int error = assign_type(fl, arg);	if (error < 0)		goto out;	locks_wake_up_blocks(fl, 0);	if (arg == F_UNLCK) {		filp->f_owner.pid = 0;		filp->f_owner.uid = 0;		filp->f_owner.euid = 0;		filp->f_owner.signum = 0;		locks_delete_lock(before, 0);		fasync_helper(fd, filp, 0, &fl->fl_fasync);	}out:	return error;}/** *	fcntl_setlease	-	sets a lease on an open file *	@fd: open file descriptor *	@filp: file pointer *	@arg: type of lease to obtain * *	Call this fcntl to establish a lease on the file. *	Note that you also need to call %F_SETSIG to *	receive a signal when the lease is broken. */int fcntl_setlease(unsigned int fd, struct file *filp, long arg){	struct file_lock *fl, **before, **my_before = NULL;	struct dentry *dentry;	struct inode *inode;	int error, rdlease_count = 0, wrlease_count = 0;	dentry = filp->f_dentry;	inode = dentry->d_inode;	if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))		return -EACCES;	if (!S_ISREG(inode->i_mode))		return -EINVAL;	/*	 * FIXME: What about F_RDLCK and files open for writing?	 */	if ((arg == F_WRLCK)	    && ((atomic_read(&dentry->d_count) > 1)		|| (atomic_read(&inode->i_count) > 1)))		return -EAGAIN;	before = &inode->i_flock;	lock_kernel();	while ((fl = *before) != NULL) {		if (fl->fl_flags != FL_LEASE)			break;		if (fl->fl_file == filp)			my_before = before;		else if (fl->fl_type & F_WRLCK)			wrlease_count++;		else			rdlease_count++;		before = &fl->fl_next;	}	if ((arg == F_RDLCK && (wrlease_count > 0)) ||	    (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) {		error = -EAGAIN;		goto out_unlock;	}	if (my_before != NULL) {		error = lease_modify(my_before, arg, fd, filp);		goto out_unlock;	}	if (arg == F_UNLCK) {		error = 0;		goto out_unlock;	}	if (!leases_enable) {		error = -EINVAL;		goto out_unlock;	}	error = lease_alloc(filp, arg, &fl);	if (error)		goto out_unlock;	error = fasync_helper(fd, filp, 1, &fl->fl_fasync);	if (error < 0) {		locks_free_lock(fl);		goto out_unlock;	}	fl->fl_next = *before;	*before = fl;	list_add(&fl->fl_link, &file_lock_list);	filp->f_owner.pid = current->pid;	filp->f_owner.uid = current->uid;	filp->f_owner.euid = current->euid;out_unlock:	unlock_kernel();	return error;}/** *	sys_flock: - flock() system call. *	@fd: the file descriptor to lock. *	@cmd: the type of lock to apply. * *	Apply a %FL_FLOCK style lock to an open file descriptor. *	The @cmd can be one of * *	%LOCK_SH -- a shared lock. * *	%LOCK_EX -- an exclusive lock. * *	%LOCK_UN -- remove an existing lock. * *	%LOCK_MAND -- a `mandatory' flock.  This exists to emulate Windows Share Modes. * *	%LOCK_MAND can be combined with %LOCK_READ or %LOCK_WRITE to allow other *	processes read and write access respectively. */asmlinkage long sys_flock(unsigned int fd, unsigned int cmd){	struct file *filp;	int error, type;	error = -EBADF;	filp = fget(fd);	if (!filp)		goto out;	error = flock_translate_cmd(cmd);	if (error < 0)		goto out_putf;	type = error;	error = -EBADF;	if ((type != F_UNLCK)#ifdef MSNFS		&& !(type & LOCK_MAND)#endif		&& !(filp->f_mode & 3))		goto out_putf;	lock_kernel();	error = flock_lock_file(filp, type,				(cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);	unlock_kernel();out_putf:	fput(filp);out:	return error;}/* 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){	struct file *filp;	struct file_lock *fl, file_lock;	struct flock flock;	int error;	error = -EFAULT;	if (copy_from_user(&flock, l, sizeof(flock)))		goto out;	error = -EINVAL;	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))		goto out;	error = -EBADF;	filp = fget(fd);	if (!filp)		goto out;	error = flock_to_posix_lock(filp, &file_lock, &flock);	if (error)		goto out_putf;	if (filp->f_op && filp->f_op->lock) {		error = filp->f_op->lock(filp, F_GETLK, &file_lock);		if (error < 0)			goto out_putf;		else if (error == LOCK_USE_CLNT)		  /* Bypass for NFS with no locking - 2.0.36 compat */		  fl = posix_test_lock(filp, &file_lock);		else		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);	} else {		fl = posix_test_lock(filp, &file_lock);	} 	flock.l_type = F_UNLCK;	if (fl != NULL) {		flock.l_pid = fl->fl_pid;#if BITS_PER_LONG == 32		/*		 * Make sure we can represent the posix lock via		 * legacy 32bit flock.		 */		error = -EOVERFLOW;		if (fl->fl_start > OFFT_OFFSET_MAX)			goto out_putf;		if ((fl->fl_end != OFFSET_MAX)		    && (fl->fl_end > OFFT_OFFSET_MAX))			goto out_putf;#endif		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;	}	error = -EFAULT;	if (!copy_to_user(l, &flock, sizeof(flock)))		error = 0;  out_putf:	fput(filp);out:	return error;}/* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l){	struct file *filp;	struct file_lock *file_lock = locks_alloc_lock(0);	struct flock flock;	struct inode *inode;	int error;	if (file_lock == NULL)		return -ENOLCK;	/*	 * This might block, so we do it before checking the inode.	 */	error = -EFAULT;	if (copy_from_user(&flock, l, sizeof(flock)))		goto out;	/* Get arguments and validate them ...	 */	error = -EBADF;	filp = fget(fd);	if (!filp)		goto out;	error = -EINVAL;	inode = filp->f_dentry->d_inode;	/* Don't allow mandatory locks on files that may be memory mapped	 * and shared.	 */	if (IS_MANDLOCK(inode) &&	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {		struct address_space *mapping = inode->i_mapping;		if (mapping->i_mmap_shared != NULL) {			error = -EAGAIN;			goto out_putf;

⌨️ 快捷键说明

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