Пример #1
0
int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
{
	struct dnotify_struct *dn;
	struct dnotify_struct *odn;
	struct dnotify_struct **prev;
	struct inode *inode;
	fl_owner_t id = current->files;
	int error = 0;

	if ((arg & ~DN_MULTISHOT) == 0) {
		dnotify_flush(filp, id);
		return 0;
	}
	if (!dir_notify_enable)
		return -EINVAL;
	inode = filp->f_dentry->d_inode;
	if (!S_ISDIR(inode->i_mode))
		return -ENOTDIR;
	dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
	if (dn == NULL)
		return -ENOMEM;
	spin_lock(&inode->i_lock);
	prev = &inode->i_dnotify;
	while ((odn = *prev) != NULL) {
		if ((odn->dn_owner == id) && (odn->dn_filp == filp)) {
			odn->dn_fd = fd;
			odn->dn_mask |= arg;
			inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
			goto out_free;
		}
		prev = &odn->dn_next;
	}

	error = f_setown(filp, current->pid, 0);
	if (error)
		goto out_free;

	dn->dn_mask = arg;
	dn->dn_fd = fd;
	dn->dn_filp = filp;
	dn->dn_owner = id;
	inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
	dn->dn_next = inode->i_dnotify;
	inode->i_dnotify = dn;
	spin_unlock(&inode->i_lock);

	if (filp->f_op && filp->f_op->dir_notify)
		return filp->f_op->dir_notify(filp, arg);
	return 0;

out_free:
	spin_unlock(&inode->i_lock);
	kmem_cache_free(dn_cache, dn);
	return error;
}
Пример #2
0
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                     struct file *filp)
{
    long err = -EINVAL;

    switch (cmd) {
    case F_DUPFD:
        err = f_dupfd(arg, filp, 0);
        break;
    case F_DUPFD_CLOEXEC:
        err = f_dupfd(arg, filp, O_CLOEXEC);
        break;
    case F_GETFD:
        err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
        break;
    case F_SETFD:
        err = 0;
        set_close_on_exec(fd, arg & FD_CLOEXEC);
        break;
    case F_GETFL:
        err = filp->f_flags;
        break;
    case F_SETFL:
        err = setfl(fd, filp, arg);
        break;
#if BITS_PER_LONG != 32
    /* 32-bit arches must use fcntl64() */
    case F_OFD_GETLK:
#endif
    case F_GETLK:
        err = fcntl_getlk(filp, cmd, (struct flock __user *) arg);
        break;
#if BITS_PER_LONG != 32
    /* 32-bit arches must use fcntl64() */
    case F_OFD_SETLK:
    case F_OFD_SETLKW:
#endif
    /* Fallthrough */
    case F_SETLK:
    case F_SETLKW:
        err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg);
        break;
    case F_GETOWN:
        /*
         * XXX If f_owner is a process group, the
         * negative return value will get converted
         * into an error.  Oops.  If we keep the
         * current syscall conventions, the only way
         * to fix this will be in libc.
         */
        err = f_getown(filp);
        force_successful_syscall_return();
        break;
    case F_SETOWN:
        err = f_setown(filp, arg, 1);
        break;
    case F_GETOWN_EX:
        err = f_getown_ex(filp, arg);
        break;
    case F_SETOWN_EX:
        err = f_setown_ex(filp, arg);
        break;
    case F_GETOWNER_UIDS:
        err = f_getowner_uids(filp, arg);
        break;
    case F_GETSIG:
        err = filp->f_owner.signum;
        break;
    case F_SETSIG:
        /* arg == 0 restores default behaviour. */
        if (!valid_signal(arg)) {
            break;
        }
        err = 0;
        filp->f_owner.signum = arg;
        break;
    case F_GETLEASE:
        err = fcntl_getlease(filp);
        break;
    case F_SETLEASE:
        err = fcntl_setlease(fd, filp, arg);
        break;
    case F_NOTIFY:
        err = fcntl_dirnotify(fd, filp, arg);
        break;
    case F_SETPIPE_SZ:
    case F_GETPIPE_SZ:
        err = pipe_fcntl(filp, cmd, arg);
        break;
    case F_ADD_SEALS:
    case F_GET_SEALS:
        err = shmem_fcntl(filp, cmd, arg);
        break;
    default:
        break;
    }
    return err;
}
Пример #3
0
int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
{
	struct dnotify_struct *dn;
	struct dnotify_struct *odn;
	struct dnotify_struct **prev;
	struct inode *inode;
	fl_owner_t id = current->files;
	struct file *f;
	int error = 0;

	if ((arg & ~DN_MULTISHOT) == 0) {
		dnotify_flush(filp, id);
		return 0;
	}
	if (!dir_notify_enable)
		return -EINVAL;
	inode = filp->f_dentry->d_inode;
	if (!S_ISDIR(inode->i_mode))
		return -ENOTDIR;
	dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
	if (dn == NULL)
		return -ENOMEM;
	spin_lock(&inode->i_lock);
	prev = &inode->i_dnotify;
	while ((odn = *prev) != NULL) {
		if ((odn->dn_owner == id) && (odn->dn_filp == filp)) {
			odn->dn_fd = fd;
			odn->dn_mask |= arg;
			inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
			goto out_free;
		}
		prev = &odn->dn_next;
	}

	rcu_read_lock();
	f = fcheck(fd);
	rcu_read_unlock();
	/* we'd lost the race with close(), sod off silently */
	/* note that inode->i_lock prevents reordering problems
	 * between accesses to descriptor table and ->i_dnotify */
	if (f != filp)
		goto out_free;

	error = f_setown(filp, current->pid, 0);
	if (error)
		goto out_free;

	dn->dn_mask = arg;
	dn->dn_fd = fd;
	dn->dn_filp = filp;
	dn->dn_owner = id;
	inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
	dn->dn_next = inode->i_dnotify;
	inode->i_dnotify = dn;
	spin_unlock(&inode->i_lock);

	if (filp->f_op && filp->f_op->dir_notify)
		return filp->f_op->dir_notify(filp, arg);
	return 0;

out_free:
	spin_unlock(&inode->i_lock);
	kmem_cache_free(dn_cache, dn);
	return error;
}