Skip to content

Commit

Permalink
Merge branch 'upstream-linus' of git://oss.oracle.com/home/sourcebo/g…
Browse files Browse the repository at this point in the history
…it/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
  • Loading branch information
Linus Torvalds committed May 17, 2006
2 parents a5d1792 + cef0893 commit 15eb710
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 86 deletions.
2 changes: 1 addition & 1 deletion fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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/
137 changes: 96 additions & 41 deletions fs/configfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -748,40 +774,67 @@ 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) {
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 (!type) {
ret = -EINVAL;
goto out_unlink;
}

if (ret) {
down(&subsys->su_sem);
if (group)
unlink_group(group);
else
unlink_obj(item);
client_drop_item(parent_item, item);
up(&subsys->su_sem);
owner = type->ct_owner;
if (!try_module_get(owner)) {
ret = -EINVAL;
goto out_unlink;
}

config_item_put(parent_item);
module_put(owner);
}
}
/*
* 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);
else
unlink_obj(item);
client_drop_item(parent_item, item);
up(&subsys->su_sem);

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;
}

Expand All @@ -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);
Expand All @@ -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. */
Expand Down
46 changes: 39 additions & 7 deletions fs/ocfs2/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,29 @@ 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,
unsigned from, unsigned to)
static int ocfs2_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
struct inode *inode = page->mapping->host;
int ret;
Expand All @@ -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:
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions fs/ocfs2/aops.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
#ifndef OCFS2_AOPS_H
#define OCFS2_AOPS_H

int ocfs2_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to);
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,
struct page *page,
Expand Down
6 changes: 3 additions & 3 deletions fs/ocfs2/extent_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
Loading

0 comments on commit 15eb710

Please sign in to comment.