Coda: push BKL regions into coda_upcall()
Now that shared inode state is locked using the cii->c_lock, the BKL is
only used to protect the upcall queues used to communicate with the
userspace cache manager. The remaining state is all local and we can
push the lock further down into coda_upcall().
Signed-off-by: Yoshihisa Abe <yoshiabe@cs.cmu.edu>
Signed-off-by: Jan Harkes <jaharkes@cs.cmu.edu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 69fbbea..96fbeab 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -17,7 +17,6 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
@@ -117,15 +116,11 @@
goto exit;
}
- lock_kernel();
-
error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
&type, &resfid);
if (!error)
error = coda_cnode_make(&inode, &resfid, dir->i_sb);
- unlock_kernel();
-
if (error && error != -ENOENT)
return ERR_PTR(error);
@@ -141,28 +136,24 @@
int coda_permission(struct inode *inode, int mask)
{
- int error = 0;
+ int error;
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
if (!mask)
- return 0;
+ return 0;
if ((mask & MAY_EXEC) && !execute_ok(inode))
return -EACCES;
- lock_kernel();
-
if (coda_cache_check(inode, mask))
- goto out;
+ return 0;
- error = venus_access(inode->i_sb, coda_i2f(inode), mask);
+ error = venus_access(inode->i_sb, coda_i2f(inode), mask);
if (!error)
coda_cache_enter(inode, mask);
- out:
- unlock_kernel();
return error;
}
@@ -201,41 +192,34 @@
/* creation routines: create, mknod, mkdir, link, symlink */
static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd)
{
- int error=0;
+ int error;
const char *name=de->d_name.name;
int length=de->d_name.len;
struct inode *inode;
struct CodaFid newfid;
struct coda_vattr attrs;
- lock_kernel();
-
- if (coda_isroot(dir) && coda_iscontrol(name, length)) {
- unlock_kernel();
+ if (coda_isroot(dir) && coda_iscontrol(name, length))
return -EPERM;
- }
error = venus_create(dir->i_sb, coda_i2f(dir), name, length,
0, mode, &newfid, &attrs);
-
- if ( error ) {
- unlock_kernel();
- d_drop(de);
- return error;
- }
+ if (error)
+ goto err_out;
inode = coda_iget(dir->i_sb, &newfid, &attrs);
- if ( IS_ERR(inode) ) {
- unlock_kernel();
- d_drop(de);
- return PTR_ERR(inode);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto err_out;
}
/* invalidate the directory cnode's attributes */
coda_dir_update_mtime(dir);
- unlock_kernel();
d_instantiate(de, inode);
return 0;
+err_out:
+ d_drop(de);
+ return error;
}
static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
@@ -247,36 +231,29 @@
int error;
struct CodaFid newfid;
- lock_kernel();
-
- if (coda_isroot(dir) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir) && coda_iscontrol(name, len))
return -EPERM;
- }
attrs.va_mode = mode;
error = venus_mkdir(dir->i_sb, coda_i2f(dir),
name, len, &newfid, &attrs);
-
- if ( error ) {
- unlock_kernel();
- d_drop(de);
- return error;
- }
+ if (error)
+ goto err_out;
inode = coda_iget(dir->i_sb, &newfid, &attrs);
- if ( IS_ERR(inode) ) {
- unlock_kernel();
- d_drop(de);
- return PTR_ERR(inode);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto err_out;
}
/* invalidate the directory cnode's attributes */
coda_dir_inc_nlink(dir);
coda_dir_update_mtime(dir);
- unlock_kernel();
d_instantiate(de, inode);
return 0;
+err_out:
+ d_drop(de);
+ return error;
}
/* try to make de an entry in dir_inodde linked to source_de */
@@ -288,52 +265,38 @@
int len = de->d_name.len;
int error;
- lock_kernel();
-
- if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
- }
error = venus_link(dir_inode->i_sb, coda_i2f(inode),
coda_i2f(dir_inode), (const char *)name, len);
-
if (error) {
d_drop(de);
- goto out;
+ return error;
}
coda_dir_update_mtime(dir_inode);
atomic_inc(&inode->i_count);
d_instantiate(de, inode);
inc_nlink(inode);
-
-out:
- unlock_kernel();
- return(error);
+ return 0;
}
static int coda_symlink(struct inode *dir_inode, struct dentry *de,
const char *symname)
{
- const char *name = de->d_name.name;
+ const char *name = de->d_name.name;
int len = de->d_name.len;
int symlen;
- int error = 0;
+ int error;
- lock_kernel();
-
- if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
- }
symlen = strlen(symname);
- if ( symlen > CODA_MAXPATHLEN ) {
- unlock_kernel();
+ if (symlen > CODA_MAXPATHLEN)
return -ENAMETOOLONG;
- }
/*
* This entry is now negative. Since we do not create
@@ -344,10 +307,9 @@
symname, symlen);
/* mtime is no good anymore */
- if ( !error )
+ if (!error)
coda_dir_update_mtime(dir_inode);
- unlock_kernel();
return error;
}
@@ -358,17 +320,12 @@
const char *name = de->d_name.name;
int len = de->d_name.len;
- lock_kernel();
-
error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
- if ( error ) {
- unlock_kernel();
+ if (error)
return error;
- }
coda_dir_update_mtime(dir);
drop_nlink(de->d_inode);
- unlock_kernel();
return 0;
}
@@ -378,8 +335,6 @@
int len = de->d_name.len;
int error;
- lock_kernel();
-
error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
if (!error) {
/* VFS may delete the child */
@@ -390,7 +345,6 @@
coda_dir_drop_nlink(dir);
coda_dir_update_mtime(dir);
}
- unlock_kernel();
return error;
}
@@ -404,15 +358,12 @@
int new_length = new_dentry->d_name.len;
int error;
- lock_kernel();
-
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
coda_i2f(new_dir), old_length, new_length,
(const char *) old_name, (const char *)new_name);
-
- if ( !error ) {
- if ( new_dentry->d_inode ) {
- if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
+ if (!error) {
+ if (new_dentry->d_inode) {
+ if (S_ISDIR(new_dentry->d_inode->i_mode)) {
coda_dir_drop_nlink(old_dir);
coda_dir_inc_nlink(new_dir);
}
@@ -424,8 +375,6 @@
coda_flag_inode(new_dir, C_VATTR);
}
}
- unlock_kernel();
-
return error;
}
@@ -595,10 +544,7 @@
struct inode *inode = de->d_inode;
struct coda_inode_info *cii;
- if (!inode)
- return 1;
- lock_kernel();
- if (coda_isroot(inode))
+ if (!inode || coda_isroot(inode))
goto out;
if (is_bad_inode(inode))
goto bad;
@@ -621,12 +567,9 @@
spin_lock(&cii->c_lock);
cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
spin_unlock(&cii->c_lock);
-
bad:
- unlock_kernel();
return 0;
out:
- unlock_kernel();
return 1;
}
@@ -659,20 +602,19 @@
int coda_revalidate_inode(struct dentry *dentry)
{
struct coda_vattr attr;
- int error = 0;
+ int error;
int old_mode;
ino_t old_ino;
struct inode *inode = dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
- lock_kernel();
- if ( !cii->c_flags )
- goto ok;
+ if (!cii->c_flags)
+ return 0;
if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
- if ( error )
- goto return_bad;
+ if (error)
+ return -EIO;
/* this inode may be lost if:
- it's ino changed
@@ -691,7 +633,7 @@
/* the following can happen when a local fid is replaced
with a global one, here we lose and declare the inode bad */
if (inode->i_ino != old_ino)
- goto return_bad;
+ return -EIO;
coda_flag_inode_children(inode, C_FLUSH);
@@ -699,12 +641,5 @@
cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
spin_unlock(&cii->c_lock);
}
-
-ok:
- unlock_kernel();
return 0;
-
-return_bad:
- unlock_kernel();
- return -EIO;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index c4e3957..c8b50ba 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -15,7 +15,6 @@
#include <linux/stat.h>
#include <linux/cred.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -144,8 +143,6 @@
if (!cfi)
return -ENOMEM;
- lock_kernel();
-
error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
&host_file);
if (!host_file)
@@ -153,7 +150,6 @@
if (error) {
kfree(cfi);
- unlock_kernel();
return error;
}
@@ -165,8 +161,6 @@
BUG_ON(coda_file->private_data != NULL);
coda_file->private_data = cfi;
-
- unlock_kernel();
return 0;
}
@@ -177,9 +171,7 @@
struct coda_file_info *cfi;
struct coda_inode_info *cii;
struct inode *host_inode;
- int err = 0;
-
- lock_kernel();
+ int err;
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
@@ -203,8 +195,6 @@
kfree(coda_file->private_data);
coda_file->private_data = NULL;
- unlock_kernel();
-
/* VFS fput ignores the return value from file_operations->release, so
* there is no use returning an error here */
return 0;
@@ -215,7 +205,7 @@
struct file *host_file;
struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
struct coda_file_info *cfi;
- int err = 0;
+ int err;
if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
S_ISLNK(coda_inode->i_mode)))
@@ -226,11 +216,8 @@
host_file = cfi->cfi_container;
err = vfs_fsync(host_file, datasync);
- if ( !err && !datasync ) {
- lock_kernel();
+ if (!err && !datasync)
err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
- unlock_kernel();
- }
return err;
}
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 0553f3b..b7fa3e3 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -150,8 +150,6 @@
int error;
int idx;
- lock_kernel();
-
idx = get_device_index((struct coda_mount_data *) data);
/* Ignore errors in data, for backward compatibility */
@@ -161,23 +159,26 @@
printk(KERN_INFO "coda_read_super: device index: %i\n", idx);
vc = &coda_comms[idx];
+ lock_kernel();
+
if (!vc->vc_inuse) {
printk("coda_read_super: No pseudo device\n");
- unlock_kernel();
- return -EINVAL;
+ error = -EINVAL;
+ goto unlock_out;
}
- if ( vc->vc_sb ) {
+ if (vc->vc_sb) {
printk("coda_read_super: Device already mounted\n");
- unlock_kernel();
- return -EBUSY;
+ error = -EBUSY;
+ goto unlock_out;
}
error = bdi_setup_and_register(&vc->bdi, "coda", BDI_CAP_MAP_COPY);
if (error)
- goto bdi_err;
+ goto unlock_out;
vc->vc_sb = sb;
+ unlock_kernel();
sb->s_fs_info = vc;
sb->s_flags |= MS_NOATIME;
@@ -206,21 +207,23 @@
printk("coda_read_super: rootinode is %ld dev %s\n",
root->i_ino, root->i_sb->s_id);
sb->s_root = d_alloc_root(root);
- if (!sb->s_root)
+ if (!sb->s_root) {
+ error = -EINVAL;
goto error;
- unlock_kernel();
+ }
return 0;
- error:
- bdi_destroy(&vc->bdi);
- bdi_err:
+error:
if (root)
iput(root);
- if (vc)
- vc->vc_sb = NULL;
+ lock_kernel();
+ bdi_destroy(&vc->bdi);
+ vc->vc_sb = NULL;
+ sb->s_fs_info = NULL;
+unlock_out:
unlock_kernel();
- return -EINVAL;
+ return error;
}
static void coda_put_super(struct super_block *sb)
@@ -253,8 +256,6 @@
struct coda_vattr vattr;
int error;
- lock_kernel();
-
memset(&vattr, 0, sizeof(vattr));
inode->i_ctime = CURRENT_TIME_SEC;
@@ -264,13 +265,10 @@
/* Venus is responsible for truncating the container-file!!! */
error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
- if ( !error ) {
+ if (!error) {
coda_vattr_to_iattr(inode, &vattr);
coda_cache_clear_inode(inode);
}
-
- unlock_kernel();
-
return error;
}
@@ -284,12 +282,8 @@
{
int error;
- lock_kernel();
-
error = venus_statfs(dentry, buf);
- unlock_kernel();
-
if (error) {
/* fake something like AFS does */
buf->f_blocks = 9000000;
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 028a9a0..2fd89b5 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -23,8 +23,6 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/smp_lock.h>
-
/* pioctl ops */
static int coda_ioctl_permission(struct inode *inode, int mask);
static long coda_pioctl(struct file *filp, unsigned int cmd,
@@ -58,13 +56,9 @@
struct inode *target_inode = NULL;
struct coda_inode_info *cnp;
- lock_kernel();
-
/* get the Pioctl data arguments from user space */
- if (copy_from_user(&data, (void __user *)user_data, sizeof(data))) {
- error = -EINVAL;
- goto out;
- }
+ if (copy_from_user(&data, (void __user *)user_data, sizeof(data)))
+ return -EINVAL;
/*
* Look up the pathname. Note that the pathname is in
@@ -76,13 +70,12 @@
error = user_lpath(data.path, &path);
if (error)
- goto out;
- else
- target_inode = path.dentry->d_inode;
+ return error;
+
+ target_inode = path.dentry->d_inode;
/* return if it is not a Coda inode */
if (target_inode->i_sb != inode->i_sb) {
- path_put(&path);
error = -EINVAL;
goto out;
}
@@ -91,10 +84,7 @@
cnp = ITOC(target_inode);
error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
-
- path_put(&path);
-
out:
- unlock_kernel();
+ path_put(&path);
return error;
}
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index fdc2f3e..9a9248e 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -108,16 +108,9 @@
return -EFAULT;
if (DOWNCALL(hdr.opcode)) {
- struct super_block *sb = NULL;
- union outputArgs *dcbuf;
+ union outputArgs *dcbuf;
int size = sizeof(*dcbuf);
- sb = vcp->vc_sb;
- if ( !sb ) {
- count = nbytes;
- goto out;
- }
-
if ( nbytes < sizeof(struct coda_out_hdr) ) {
printk("coda_downcall opc %d uniq %d, not enough!\n",
hdr.opcode, hdr.unique);
@@ -137,9 +130,7 @@
}
/* what downcall errors does Venus handle ? */
- lock_kernel();
- error = coda_downcall(hdr.opcode, dcbuf, sb);
- unlock_kernel();
+ error = coda_downcall(vcp, hdr.opcode, dcbuf);
CODA_FREE(dcbuf, nbytes);
if (error) {
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index 4513b7258..af78f00 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -14,7 +14,6 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
@@ -29,11 +28,9 @@
unsigned int len = PAGE_SIZE;
char *p = kmap(page);
- lock_kernel();
cii = ITOC(inode);
error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
- unlock_kernel();
if (error)
goto fail;
SetPageUptodate(page);
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index b8893ab..4c258cb 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -27,6 +27,7 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/vfs.h>
@@ -667,18 +668,23 @@
{
union outputArgs *out;
union inputArgs *sig_inputArgs;
- struct upc_req *req, *sig_req;
- int error = 0;
+ struct upc_req *req = NULL, *sig_req;
+ int error;
+
+ lock_kernel();
if (!vcp->vc_inuse) {
printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
- return -ENXIO;
+ error = -ENXIO;
+ goto exit;
}
/* Format the request message. */
req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
- if (!req)
- return -ENOMEM;
+ if (!req) {
+ error = -ENOMEM;
+ goto exit;
+ }
req->uc_data = (void *)buffer;
req->uc_flags = 0;
@@ -759,6 +765,7 @@
exit:
kfree(req);
+ unlock_kernel();
return error;
}
@@ -796,21 +803,24 @@
*
* CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
-int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
{
struct inode *inode = NULL;
struct CodaFid *fid, *newfid;
+ struct super_block *sb;
/* Handle invalidation requests. */
- if ( !sb || !sb->s_root)
- return 0;
+ lock_kernel();
+ sb = vcp->vc_sb;
+ if (!sb || !sb->s_root)
+ goto unlock_out;
switch (opcode) {
case CODA_FLUSH:
coda_cache_clear_all(sb);
shrink_dcache_sb(sb);
if (sb->s_root->d_inode)
- coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
+ coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
break;
case CODA_PURGEUSER:
@@ -855,9 +865,11 @@
break;
}
+unlock_out:
+ unlock_kernel();
+
if (inode)
iput(inode);
-
return 0;
}