Commit 49233c41 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull dcache fixes from Al Viro:
 "A couple of regression fixes for the tree-in-dcache series this cycle"

* tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  functionfs: use spinlock for FFS_DEACTIVATED/FFS_CLOSING transitions
  rust_binderfs: fix a dentry leak
parents 8fdb05de 2005aabe
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -391,12 +391,6 @@ static int binderfs_binder_ctl_create(struct super_block *sb)
	if (!device)
		return -ENOMEM;

	/* If we have already created a binder-control node, return. */
	if (info->control_dentry) {
		ret = 0;
		goto out;
	}

	ret = -ENOMEM;
	inode = new_inode(sb);
	if (!inode)
@@ -431,7 +425,8 @@ static int binderfs_binder_ctl_create(struct super_block *sb)

	inode->i_private = device;
	info->control_dentry = dentry;
	d_add(dentry, inode);
	d_make_persistent(dentry, inode);
	dput(dentry);

	return 0;

+52 −56
Original line number Diff line number Diff line
@@ -59,7 +59,6 @@ static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
	__attribute__((malloc));

/* Opened counter handling. */
static void ffs_data_opened(struct ffs_data *ffs);
static void ffs_data_closed(struct ffs_data *ffs);

/* Called with ffs->mutex held; take over ownership of data. */
@@ -636,23 +635,25 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
	return ret;
}


static void ffs_data_reset(struct ffs_data *ffs);

static int ffs_ep0_open(struct inode *inode, struct file *file)
{
	struct ffs_data *ffs = inode->i_sb->s_fs_info;
	int ret;

	/* Acquire mutex */
	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
	if (ret < 0)
		return ret;

	ffs_data_opened(ffs);
	spin_lock_irq(&ffs->eps_lock);
	if (ffs->state == FFS_CLOSING) {
		ffs_data_closed(ffs);
		mutex_unlock(&ffs->mutex);
		spin_unlock_irq(&ffs->eps_lock);
		return -EBUSY;
	}
	mutex_unlock(&ffs->mutex);
	if (!ffs->opened++ && ffs->state == FFS_DEACTIVATED) {
		ffs->state = FFS_CLOSING;
		spin_unlock_irq(&ffs->eps_lock);
		ffs_data_reset(ffs);
	} else {
		spin_unlock_irq(&ffs->eps_lock);
	}
	file->private_data = ffs;

	return stream_open(inode, file);
@@ -1202,15 +1203,10 @@ ffs_epfile_open(struct inode *inode, struct file *file)
{
	struct ffs_data *ffs = inode->i_sb->s_fs_info;
	struct ffs_epfile *epfile;
	int ret;

	/* Acquire mutex */
	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
	if (ret < 0)
		return ret;

	if (!atomic_inc_not_zero(&ffs->opened)) {
		mutex_unlock(&ffs->mutex);
	spin_lock_irq(&ffs->eps_lock);
	if (!ffs->opened) {
		spin_unlock_irq(&ffs->eps_lock);
		return -ENODEV;
	}
	/*
@@ -1220,11 +1216,11 @@ ffs_epfile_open(struct inode *inode, struct file *file)
	 */
	epfile = smp_load_acquire(&inode->i_private);
	if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) {
		mutex_unlock(&ffs->mutex);
		ffs_data_closed(ffs);
		spin_unlock_irq(&ffs->eps_lock);
		return -ENODEV;
	}
	mutex_unlock(&ffs->mutex);
	ffs->opened++;
	spin_unlock_irq(&ffs->eps_lock);

	file->private_data = epfile;
	return stream_open(inode, file);
@@ -2092,8 +2088,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
	return 0;
}

static void ffs_data_reset(struct ffs_data *ffs);

static void
ffs_fs_kill_sb(struct super_block *sb)
{
@@ -2150,15 +2144,6 @@ static void ffs_data_get(struct ffs_data *ffs)
	refcount_inc(&ffs->ref);
}

static void ffs_data_opened(struct ffs_data *ffs)
{
	if (atomic_add_return(1, &ffs->opened) == 1 &&
			ffs->state == FFS_DEACTIVATED) {
		ffs->state = FFS_CLOSING;
		ffs_data_reset(ffs);
	}
}

static void ffs_data_put(struct ffs_data *ffs)
{
	if (refcount_dec_and_test(&ffs->ref)) {
@@ -2176,17 +2161,18 @@ static void ffs_data_put(struct ffs_data *ffs)

static void ffs_data_closed(struct ffs_data *ffs)
{
	if (atomic_dec_and_test(&ffs->opened)) {
	spin_lock_irq(&ffs->eps_lock);
	if (--ffs->opened) {	// not the last opener?
		spin_unlock_irq(&ffs->eps_lock);
		return;
	}
	if (ffs->no_disconnect) {
		struct ffs_epfile *epfiles;
			unsigned long flags;

		ffs->state = FFS_DEACTIVATED;
			spin_lock_irqsave(&ffs->eps_lock, flags);
		epfiles = ffs->epfiles;
		ffs->epfiles = NULL;
			spin_unlock_irqrestore(&ffs->eps_lock,
							flags);
		spin_unlock_irq(&ffs->eps_lock);

		if (epfiles)
			ffs_epfiles_destroy(ffs->sb, epfiles,
@@ -2196,10 +2182,10 @@ static void ffs_data_closed(struct ffs_data *ffs)
			__ffs_ep0_stall(ffs);
	} else {
		ffs->state = FFS_CLOSING;
		spin_unlock_irq(&ffs->eps_lock);
		ffs_data_reset(ffs);
	}
}
}

static struct ffs_data *ffs_data_new(const char *dev_name)
{
@@ -2214,7 +2200,7 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
	}

	refcount_set(&ffs->ref, 1);
	atomic_set(&ffs->opened, 0);
	ffs->opened = 0;
	ffs->state = FFS_READ_DESCRIPTORS;
	mutex_init(&ffs->mutex);
	spin_lock_init(&ffs->eps_lock);
@@ -2266,6 +2252,7 @@ static void ffs_data_reset(struct ffs_data *ffs)
{
	ffs_data_clear(ffs);

	spin_lock_irq(&ffs->eps_lock);
	ffs->raw_descs_data = NULL;
	ffs->raw_descs = NULL;
	ffs->raw_strings = NULL;
@@ -2289,6 +2276,7 @@ static void ffs_data_reset(struct ffs_data *ffs)
	ffs->ms_os_descs_ext_prop_count = 0;
	ffs->ms_os_descs_ext_prop_name_len = 0;
	ffs->ms_os_descs_ext_prop_data_len = 0;
	spin_unlock_irq(&ffs->eps_lock);
}


@@ -3756,6 +3744,7 @@ static int ffs_func_set_alt(struct usb_function *f,
{
	struct ffs_function *func = ffs_func_from_usb(f);
	struct ffs_data *ffs = func->ffs;
	unsigned long flags;
	int ret = 0, intf;

	if (alt > MAX_ALT_SETTINGS)
@@ -3768,12 +3757,15 @@ static int ffs_func_set_alt(struct usb_function *f,
	if (ffs->func)
		ffs_func_eps_disable(ffs->func);

	spin_lock_irqsave(&ffs->eps_lock, flags);
	if (ffs->state == FFS_DEACTIVATED) {
		ffs->state = FFS_CLOSING;
		spin_unlock_irqrestore(&ffs->eps_lock, flags);
		INIT_WORK(&ffs->reset_work, ffs_reset_work);
		schedule_work(&ffs->reset_work);
		return -ENODEV;
	}
	spin_unlock_irqrestore(&ffs->eps_lock, flags);

	if (ffs->state != FFS_ACTIVE)
		return -ENODEV;
@@ -3791,16 +3783,20 @@ static void ffs_func_disable(struct usb_function *f)
{
	struct ffs_function *func = ffs_func_from_usb(f);
	struct ffs_data *ffs = func->ffs;
	unsigned long flags;

	if (ffs->func)
		ffs_func_eps_disable(ffs->func);

	spin_lock_irqsave(&ffs->eps_lock, flags);
	if (ffs->state == FFS_DEACTIVATED) {
		ffs->state = FFS_CLOSING;
		spin_unlock_irqrestore(&ffs->eps_lock, flags);
		INIT_WORK(&ffs->reset_work, ffs_reset_work);
		schedule_work(&ffs->reset_work);
		return;
	}
	spin_unlock_irqrestore(&ffs->eps_lock, flags);

	if (ffs->state == FFS_ACTIVE) {
		ffs->func = NULL;
+1 −1
Original line number Diff line number Diff line
@@ -176,7 +176,7 @@ struct ffs_data {
	/* reference counter */
	refcount_t			ref;
	/* how many files are opened (EP0 and others) */
	atomic_t			opened;
	int				opened;

	/* EP0 state */
	enum ffs_state			state;