Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15eb7105 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'upstream-linus' of git://oss.oracle.com/home/sourcebo/git/ocfs2

* 'upstream-linus' of git://oss.oracle.com/home/sourcebo/git/ocfs2:
  configfs: Make sure configfs_init() is called before consumers.
  configfs: configfs_mkdir() failed to cleanup linkage.
  configfs: Fix a reference leak in configfs_mkdir().
  ocfs2: fix gfp mask in some file system paths
  ocfs2: Don't populate uptodate cache in ocfs2_force_read_journal()
  ocfs2: take meta data lock in ocfs2_file_aio_read()
  ocfs2: take data locks around extend
parents a5d17928 cef0893d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ obj-$(CONFIG_DNOTIFY) += dnotify.o
obj-$(CONFIG_PROC_FS)		+= proc/
obj-y				+= partitions/
obj-$(CONFIG_SYSFS)		+= sysfs/
obj-$(CONFIG_CONFIGFS_FS)	+= configfs/
obj-y				+= devpts/

obj-$(CONFIG_PROFILING)		+= dcookies.o
@@ -100,5 +101,4 @@ obj-$(CONFIG_BEFS_FS) += befs/
obj-$(CONFIG_HOSTFS)		+= hostfs/
obj-$(CONFIG_HPPFS)		+= hppfs/
obj-$(CONFIG_DEBUG_FS)		+= debugfs/
obj-$(CONFIG_CONFIGFS_FS)	+= configfs/
obj-$(CONFIG_OCFS2_FS)		+= ocfs2/
+96 −41
Original line number Diff line number Diff line
@@ -505,13 +505,15 @@ static int populate_groups(struct config_group *group)
	int i;

	if (group->default_groups) {
		/* FYI, we're faking mkdir here
		/*
		 * FYI, we're faking mkdir here
		 * I'm not sure we need this semaphore, as we're called
		 * from our parent's mkdir.  That holds our parent's
		 * i_mutex, so afaik lookup cannot continue through our
		 * parent to find us, let alone mess with our tree.
		 * That said, taking our i_mutex is closer to mkdir
		 * emulation, and shouldn't hurt. */
		 * emulation, and shouldn't hurt.
		 */
		mutex_lock(&dentry->d_inode->i_mutex);

		for (i = 0; group->default_groups[i]; i++) {
@@ -546,20 +548,34 @@ static void unlink_obj(struct config_item *item)

		item->ci_group = NULL;
		item->ci_parent = NULL;

		/* Drop the reference for ci_entry */
		config_item_put(item);

		/* Drop the reference for ci_parent */
		config_group_put(group);
	}
}

static void link_obj(struct config_item *parent_item, struct config_item *item)
{
	/* Parent seems redundant with group, but it makes certain
	 * traversals much nicer. */
	/*
	 * Parent seems redundant with group, but it makes certain
	 * traversals much nicer.
	 */
	item->ci_parent = parent_item;

	/*
	 * We hold a reference on the parent for the child's ci_parent
	 * link.
	 */
	item->ci_group = config_group_get(to_config_group(parent_item));
	list_add_tail(&item->ci_entry, &item->ci_group->cg_children);

	/*
	 * We hold a reference on the child for ci_entry on the parent's
	 * cg_children
	 */
	config_item_get(item);
}

@@ -684,6 +700,10 @@ static void client_drop_item(struct config_item *parent_item,
	type = parent_item->ci_type;
	BUG_ON(!type);

	/*
	 * If ->drop_item() exists, it is responsible for the
	 * config_item_put().
	 */
	if (type->ct_group_ops && type->ct_group_ops->drop_item)
		type->ct_group_ops->drop_item(to_config_group(parent_item),
						item);
@@ -694,23 +714,28 @@ static void client_drop_item(struct config_item *parent_item,

static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
	int ret;
	int ret, module_got = 0;
	struct config_group *group;
	struct config_item *item;
	struct config_item *parent_item;
	struct configfs_subsystem *subsys;
	struct configfs_dirent *sd;
	struct config_item_type *type;
	struct module *owner;
	struct module *owner = NULL;
	char *name;

	if (dentry->d_parent == configfs_sb->s_root)
		return -EPERM;
	if (dentry->d_parent == configfs_sb->s_root) {
		ret = -EPERM;
		goto out;
	}

	sd = dentry->d_parent->d_fsdata;
	if (!(sd->s_type & CONFIGFS_USET_DIR))
		return -EPERM;
	if (!(sd->s_type & CONFIGFS_USET_DIR)) {
		ret = -EPERM;
		goto out;
	}

	/* Get a working ref for the duration of this function */
	parent_item = configfs_get_config_item(dentry->d_parent);
	type = parent_item->ci_type;
	subsys = to_config_group(parent_item)->cg_subsys;
@@ -719,15 +744,16 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
	if (!type || !type->ct_group_ops ||
	    (!type->ct_group_ops->make_group &&
	     !type->ct_group_ops->make_item)) {
		config_item_put(parent_item);
		return -EPERM;  /* What lack-of-mkdir returns */
		ret = -EPERM;  /* Lack-of-mkdir returns -EPERM */
		goto out_put;
	}

	name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL);
	if (!name) {
		config_item_put(parent_item);
		return -ENOMEM;
		ret = -ENOMEM;
		goto out_put;
	}

	snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name);

	down(&subsys->su_sem);
@@ -748,26 +774,46 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)

	kfree(name);
	if (!item) {
		config_item_put(parent_item);
		return -ENOMEM;
		/*
		 * If item == NULL, then link_obj() was never called.
		 * There are no extra references to clean up.
		 */
		ret = -ENOMEM;
		goto out_put;
	}

	ret = -EINVAL;
	/*
	 * link_obj() has been called (via link_group() for groups).
	 * From here on out, errors must clean that up.
	 */

	type = item->ci_type;
	if (type) {
	if (!type) {
		ret = -EINVAL;
		goto out_unlink;
	}

	owner = type->ct_owner;
		if (try_module_get(owner)) {
			if (group) {
				ret = configfs_attach_group(parent_item,
							    item,
							    dentry);
			} else {
				ret = configfs_attach_item(parent_item,
							   item,
							   dentry);
	if (!try_module_get(owner)) {
		ret = -EINVAL;
		goto out_unlink;
	}

	/*
	 * I hate doing it this way, but if there is
	 * an error,  module_put() probably should
	 * happen after any cleanup.
	 */
	module_got = 1;

	if (group)
		ret = configfs_attach_group(parent_item, item, dentry);
	else
		ret = configfs_attach_item(parent_item, item, dentry);

out_unlink:
	if (ret) {
		/* Tear down everything we built up */
		down(&subsys->su_sem);
		if (group)
			unlink_group(group);
@@ -776,12 +822,19 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
		client_drop_item(parent_item, item);
		up(&subsys->su_sem);

				config_item_put(parent_item);
		if (module_got)
			module_put(owner);
	}
		}
	}

out_put:
	/*
	 * link_obj()/link_group() took a reference from child->parent,
	 * so the parent is safely pinned.  We can drop our working
	 * reference.
	 */
	config_item_put(parent_item);

out:
	return ret;
}

@@ -801,6 +854,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
	if (sd->s_type & CONFIGFS_USET_DEFAULT)
		return -EPERM;

	/* Get a working ref until we have the child */
	parent_item = configfs_get_config_item(dentry->d_parent);
	subsys = to_config_group(parent_item)->cg_subsys;
	BUG_ON(!subsys);
@@ -817,6 +871,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
		return ret;
	}

	/* Get a working ref for the duration of this function */
	item = configfs_get_config_item(dentry);

	/* Drop reference from above, item already holds one. */
+39 −7
Original line number Diff line number Diff line
@@ -276,12 +276,28 @@ static int ocfs2_writepage(struct page *page, struct writeback_control *wbc)
	return ret;
}

/* This can also be called from ocfs2_write_zero_page() which has done
 * it's own cluster locking. */
int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
			       unsigned from, unsigned to)
{
	int ret;

	down_read(&OCFS2_I(inode)->ip_alloc_sem);

	ret = block_prepare_write(page, from, to, ocfs2_get_block);

	up_read(&OCFS2_I(inode)->ip_alloc_sem);

	return ret;
}

/*
 * ocfs2_prepare_write() can be an outer-most ocfs2 call when it is called
 * from loopback.  It must be able to perform its own locking around
 * ocfs2_get_block().
 */
int ocfs2_prepare_write(struct file *file, struct page *page,
static int ocfs2_prepare_write(struct file *file, struct page *page,
			       unsigned from, unsigned to)
{
	struct inode *inode = page->mapping->host;
@@ -295,11 +311,7 @@ int ocfs2_prepare_write(struct file *file, struct page *page,
		goto out;
	}

	down_read(&OCFS2_I(inode)->ip_alloc_sem);

	ret = block_prepare_write(page, from, to, ocfs2_get_block);

	up_read(&OCFS2_I(inode)->ip_alloc_sem);
	ret = ocfs2_prepare_write_nolock(inode, page, from, to);

	ocfs2_meta_unlock(inode, 0);
out:
@@ -625,11 +637,31 @@ static ssize_t ocfs2_direct_IO(int rw,
	int ret;

	mlog_entry_void();

	/*
	 * We get PR data locks even for O_DIRECT.  This allows
	 * concurrent O_DIRECT I/O but doesn't let O_DIRECT with
	 * extending and buffered zeroing writes race.  If they did
	 * race then the buffered zeroing could be written back after
	 * the O_DIRECT I/O.  It's one thing to tell people not to mix
	 * buffered and O_DIRECT writes, but expecting them to
	 * understand that file extension is also an implicit buffered
	 * write is too much.  By getting the PR we force writeback of
	 * the buffered zeroing before proceeding.
	 */
	ret = ocfs2_data_lock(inode, 0);
	if (ret < 0) {
		mlog_errno(ret);
		goto out;
	}
	ocfs2_data_unlock(inode, 0);

	ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
					    inode->i_sb->s_bdev, iov, offset,
					    nr_segs, 
					    ocfs2_direct_IO_get_blocks,
					    ocfs2_dio_end_io);
out:
	mlog_exit(ret);
	return ret;
}
+2 −2
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@
#ifndef OCFS2_AOPS_H
#define OCFS2_AOPS_H

int ocfs2_prepare_write(struct file *file, struct page *page,
int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
			       unsigned from, unsigned to);

struct ocfs2_journal_handle *ocfs2_start_walk_page_trans(struct inode *inode,
+3 −3
Original line number Diff line number Diff line
@@ -569,7 +569,7 @@ static int ocfs2_extent_map_insert(struct inode *inode,

	ret = -ENOMEM;
	ctxt.new_ent = kmem_cache_alloc(ocfs2_em_ent_cachep,
					GFP_KERNEL);
					GFP_NOFS);
	if (!ctxt.new_ent) {
		mlog_errno(ret);
		return ret;
@@ -583,14 +583,14 @@ static int ocfs2_extent_map_insert(struct inode *inode,
		if (ctxt.need_left && !ctxt.left_ent) {
			ctxt.left_ent =
				kmem_cache_alloc(ocfs2_em_ent_cachep,
						 GFP_KERNEL);
						 GFP_NOFS);
			if (!ctxt.left_ent)
				break;
		}
		if (ctxt.need_right && !ctxt.right_ent) {
			ctxt.right_ent =
				kmem_cache_alloc(ocfs2_em_ent_cachep,
						 GFP_KERNEL);
						 GFP_NOFS);
			if (!ctxt.right_ent)
				break;
		}
Loading