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

📄 locks.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
		}	}	error = flock_to_posix_lock(filp, file_lock, &flock);	if (error)		goto out_putf;		error = -EBADF;	switch (flock.l_type) {	case F_RDLCK:		if (!(filp->f_mode & FMODE_READ))			goto out_putf;		break;	case F_WRLCK:		if (!(filp->f_mode & FMODE_WRITE))			goto out_putf;		break;	case F_UNLCK:		break;	case F_SHLCK:	case F_EXLCK:#ifdef __sparc__/* 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);	}}		if (!(filp->f_mode & 3))			goto out_putf;		break;#endif	default:		error = -EINVAL;		goto out_putf;	}	if (filp->f_op && filp->f_op->lock != NULL) {		error = filp->f_op->lock(filp, cmd, file_lock);		if (error < 0)			goto out_putf;	}	error = posix_lock_file(filp, file_lock, cmd == F_SETLKW);out_putf:	fput(filp);out:	locks_free_lock(file_lock);	return error;}#if BITS_PER_LONG == 32/* Report the first existing lock that would conflict with l. * This implements the F_GETLK command of fcntl(). */int fcntl_getlk64(unsigned int fd, struct flock64 *l){	struct file *filp;	struct file_lock *fl, file_lock;	struct flock64 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 = flock64_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;		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_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l){	struct file *filp;	struct file_lock *file_lock = locks_alloc_lock(0);	struct flock64 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;		}	}	error = flock64_to_posix_lock(filp, file_lock, &flock);	if (error)		goto out_putf;		error = -EBADF;	switch (flock.l_type) {	case F_RDLCK:		if (!(filp->f_mode & FMODE_READ))			goto out_putf;		break;	case F_WRLCK:		if (!(filp->f_mode & FMODE_WRITE))			goto out_putf;		break;	case F_UNLCK:		break;	case F_SHLCK:	case F_EXLCK:	default:		error = -EINVAL;		goto out_putf;	}	if (filp->f_op && filp->f_op->lock != NULL) {		error = filp->f_op->lock(filp, cmd, file_lock);		if (error < 0)			goto out_putf;	}	error = posix_lock_file(filp, file_lock, cmd == F_SETLKW64);out_putf:	fput(filp);out:	locks_free_lock(file_lock);	return error;}#endif /* BITS_PER_LONG == 32 *//* * This function is called when the file is being removed * from the task's fd array. */void locks_remove_posix(struct file *filp, fl_owner_t owner){	struct inode * inode = filp->f_dentry->d_inode;	struct file_lock *fl;	struct file_lock **before;	/*	 * For POSIX locks we free all locks on this file for the given task.	 */	if (!inode->i_flock) {		/*		 * Notice that something might be grabbing a lock right now.		 * Consider it as a race won by us - event is async, so even if		 * we miss the lock added we can trivially consider it as added		 * after we went through this call.		 */		return;	}	lock_kernel();	before = &inode->i_flock;	while ((fl = *before) != NULL) {		if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) {			locks_unlock_delete(before);			before = &inode->i_flock;			continue;		}		before = &fl->fl_next;	}	unlock_kernel();}/* * This function is called on the last close of an open file. */void locks_remove_flock(struct file *filp){	struct inode * inode = filp->f_dentry->d_inode; 	struct file_lock *fl;	struct file_lock **before;	if (!inode->i_flock)		return;	lock_kernel();	before = &inode->i_flock;	while ((fl = *before) != NULL) {		if ((fl->fl_flags & (FL_FLOCK|FL_LEASE))		    && (fl->fl_file == filp)) {			locks_delete_lock(before, 0);			continue; 		}		before = &fl->fl_next;	}	unlock_kernel();}/** *	posix_block_lock - blocks waiting for a file lock *	@blocker: the lock which is blocking *	@waiter: the lock which conflicts and has to wait * * lockd needs to block waiting for locks. */voidposix_block_lock(struct file_lock *blocker, struct file_lock *waiter){	locks_insert_block(blocker, waiter);}/** *	posix_unblock_lock - stop waiting for a file lock *	@waiter: the lock which was waiting * *	lockd needs to block waiting for locks. */voidposix_unblock_lock(struct file_lock *waiter){	if (!list_empty(&waiter->fl_block))		locks_delete_block(waiter);}static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx){	struct inode *inode = NULL;	if (fl->fl_file != NULL)		inode = fl->fl_file->f_dentry->d_inode;	out += sprintf(out, "%d:%s ", id, pfx);	if (fl->fl_flags & FL_POSIX) {		out += sprintf(out, "%6s %s ",			     (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",			     (inode == NULL) ? "*NOINODE*" :			     (IS_MANDLOCK(inode) &&			      (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?			     "MANDATORY" : "ADVISORY ");	} else if (fl->fl_flags & FL_FLOCK) {#ifdef MSNFS		if (fl->fl_type & LOCK_MAND) {			out += sprintf(out, "FLOCK  MSNFS     ");		} else#endif			out += sprintf(out, "FLOCK  ADVISORY  ");	} else if (fl->fl_flags & FL_LEASE) {		out += sprintf(out, "LEASE  MANDATORY ");	} else {		out += sprintf(out, "UNKNOWN UNKNOWN  ");	}#ifdef MSNFS	if (fl->fl_type & LOCK_MAND) {		out += sprintf(out, "%s ",			       (fl->fl_type & LOCK_READ)			       ? (fl->fl_type & LOCK_WRITE) ? "RW   " : "READ "			       : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");	} else#endif		out += sprintf(out, "%s ",			       (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");	out += sprintf(out, "%d %s:%ld ",		     fl->fl_pid,		     inode ? kdevname(inode->i_dev) : "<none>",		     inode ? inode->i_ino : 0);	out += sprintf(out, "%Ld ", fl->fl_start);	if (fl->fl_end == OFFSET_MAX)		out += sprintf(out, "EOF ");	else		out += sprintf(out, "%Ld ", fl->fl_end);	sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n",		(long)fl, (long)fl->fl_link.prev, (long)fl->fl_link.next,		(long)fl->fl_next, (long)fl->fl_block.next);}static void move_lock_status(char **p, off_t* pos, off_t offset){	int len;	len = strlen(*p);	if(*pos >= offset) {		/* the complete line is valid */		*p += len;		*pos += len;		return;	}	if(*pos+len > offset) {		/* use the second part of the line */		int i = offset-*pos;		memmove(*p,*p+i,len-i);		*p += len-i;		*pos += len;		return;	}	/* discard the complete line */	*pos += len;}/** *	get_locks_status	-	reports lock usage in /proc/locks *	@buffer: address in userspace to write into *	@start: ? *	@offset: how far we are through the buffer *	@length: how much to read */int get_locks_status(char *buffer, char **start, off_t offset, int length){	struct list_head *tmp;	char *q = buffer;	off_t pos = 0;	int i = 0;	lock_kernel();	list_for_each(tmp, &file_lock_list) {		struct list_head *btmp;		struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);		lock_get_status(q, fl, ++i, "");		move_lock_status(&q, &pos, offset);		if(pos >= offset+length)			goto done;		list_for_each(btmp, &fl->fl_block) {			struct file_lock *bfl = list_entry(btmp,					struct file_lock, fl_block);			lock_get_status(q, bfl, i, " ->");			move_lock_status(&q, &pos, offset);			if(pos >= offset+length)				goto done;		}	}done:	unlock_kernel();	*start = buffer;	if(q-buffer < length)		return (q-buffer);	return length;}#ifdef MSNFS/** *	lock_may_read - checks that the region is free of locks *	@inode: the inode that is being read *	@start: the first byte to read *	@len: the number of bytes to read * *	Emulates Windows locking requirements.  Whole-file *	mandatory locks (share modes) can prohibit a read and *	byte-range POSIX locks can prohibit a read if they overlap. * *	N.B. this function is only ever called *	from knfsd and ownership of locks is never checked. */int lock_may_read(struct inode *inode, loff_t start, unsigned long len){	struct file_lock *fl;	int result = 1;	lock_kernel();	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {		if (fl->fl_flags == FL_POSIX) {			if (fl->fl_type == F_RDLCK)				continue;			if ((fl->fl_end < start) || (fl->fl_start > (start + len)))				continue;		} else if (fl->fl_flags == FL_FLOCK) {			if (!(fl->fl_type & LOCK_MAND))				continue;			if (fl->fl_type & LOCK_READ)				continue;		} else			continue;		result = 0;		break;	}	unlock_kernel();	return result;}/** *	lock_may_write - checks that the region is free of locks *	@inode: the inode that is being written *	@start: the first byte to write *	@len: the number of bytes to write * *	Emulates Windows locking requirements.  Whole-file *	mandatory locks (share modes) can prohibit a write and *	byte-range POSIX locks can prohibit a write if they overlap. * *	N.B. this function is only ever called *	from knfsd and ownership of locks is never checked. */int lock_may_write(struct inode *inode, loff_t start, unsigned long len){	struct file_lock *fl;	int result = 1;	lock_kernel();	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {		if (fl->fl_flags == FL_POSIX) {			if ((fl->fl_end < start) || (fl->fl_start > (start + len)))				continue;		} else if (fl->fl_flags == FL_FLOCK) {			if (!(fl->fl_type & LOCK_MAND))				continue;			if (fl->fl_type & LOCK_WRITE)				continue;		} else			continue;		result = 0;		break;	}	unlock_kernel();	return result;}#endifstatic int __init filelock_init(void){	filelock_cache = kmem_cache_create("file lock cache",			sizeof(struct file_lock), 0, 0, init_once, NULL);	if (!filelock_cache)		panic("cannot create file lock slab cache");	return 0;}module_init(filelock_init)

⌨️ 快捷键说明

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