Commit 7994321a authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] BKL shifted inside ->unlink()

	Next one in the series - this time it's ->unlink()...
parent 24b10ca2
......@@ -54,7 +54,7 @@ create: no yes
link: yes yes
mknod: no yes
mkdir: yes yes
unlink: yes yes (both)
unlink: no yes (both)
rmdir: yes yes (both) (see below)
rename: yes yes (all) (see below)
readlink: no no
......
......@@ -80,8 +80,8 @@ can relax your locking.
---
[mandatory]
->lookup(), ->truncate(), ->create() and ->mknod() are called without BKL now.
Grab it on the entry, drop upon return - that will guarantee the same
locking you used to have. If your ->method or its parts do not need
BKL - better yet, now you can shift lock_kernel()/ unlock_kernel()
so that they would protect exactly what needs to be protected.
->lookup(), ->truncate(), ->create(), ->unlink() and ->mknod() are called
without BKL now. Grab it on the entry, drop upon return - that will
guarantee the same locking you used to have. If your ->method or its
parts do not need BKL - better yet, now you can shift lock_kernel() /
unlock_kernel() so that they would protect exactly what needs to be protected.
......@@ -199,7 +199,9 @@ static int pcihpfs_unlink (struct inode *dir, struct dentry *dentry)
if (pcihpfs_empty(dentry)) {
struct inode *inode = dentry->d_inode;
lock_kernel();
inode->i_nlink--;
unlock_kernel();
dput(dentry);
error = 0;
}
......
......@@ -256,7 +256,9 @@ static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
if (usbfs_empty(dentry)) {
struct inode *inode = dentry->d_inode;
lock_kernel();
inode->i_nlink--;
unlock_kernel();
dput(dentry);
error = 0;
}
......
......@@ -253,13 +253,17 @@ affs_lookup(struct inode *dir, struct dentry *dentry)
int
affs_unlink(struct inode *dir, struct dentry *dentry)
{
int res;
pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino,
(int)dentry->d_name.len, dentry->d_name.name);
if (!dentry->d_inode)
return -ENOENT;
return affs_remove_header(dentry);
lock_kernel();
res = affs_remove_header(dentry);
unlock_kernel();
return res;
}
int
......
......@@ -332,18 +332,27 @@ static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
unsigned int n;
/* This allows root to remove symlinks */
if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
lock_kernel();
if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) {
unlock_kernel();
return -EACCES;
}
ent = autofs_hash_lookup(dh, &dentry->d_name);
if ( !ent )
if ( !ent ) {
unlock_kernel();
return -ENOENT;
}
n = ent->ino - AUTOFS_FIRST_SYMLINK;
if ( n >= AUTOFS_MAX_SYMLINKS )
if ( n >= AUTOFS_MAX_SYMLINKS ) {
unlock_kernel();
return -EISDIR; /* It's a directory, dummy */
if ( !test_bit(n,sbi->symlink_bitmap) )
}
if ( !test_bit(n,sbi->symlink_bitmap) ) {
unlock_kernel();
return -EINVAL; /* Nonexistent symlink? Shouldn't happen */
}
dentry->d_time = (unsigned long)(struct autofs_dirhash *)NULL;
autofs_hash_delete(ent);
......@@ -351,6 +360,7 @@ static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
kfree(sbi->symlink[n].data);
d_drop(dentry);
unlock_kernel();
return 0;
}
......
......@@ -376,8 +376,11 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
struct autofs_info *ino = autofs4_dentry_ino(dentry);
/* This allows root to remove symlinks */
if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
lock_kernel();
if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) {
unlock_kernel();
return -EACCES;
}
dput(ino->dentry);
......@@ -387,6 +390,8 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
dir->i_mtime = CURRENT_TIME;
d_drop(dentry);
unlock_kernel();
return 0;
}
......
......@@ -174,6 +174,7 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
struct bfs_dirent * de;
inode = dentry->d_inode;
lock_kernel();
bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
if (!bh || de->ino != inode->i_ino)
goto out_brelse;
......@@ -194,6 +195,7 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
out_brelse:
brelse(bh);
unlock_kernel();
return error;
}
......
......@@ -425,6 +425,7 @@ int coda_unlink(struct inode *dir, struct dentry *de)
const char *name = de->d_name.name;
int len = de->d_name.len;
lock_kernel();
coda_vfs_stat.unlink++;
CDEBUG(D_INODE, " %s in %s, dirino %ld\n", name ,
......@@ -433,11 +434,13 @@ int coda_unlink(struct inode *dir, struct dentry *de)
error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
if ( error ) {
CDEBUG(D_INODE, "upc returned error %d\n", error);
unlock_kernel();
return error;
}
coda_dir_changed(dir, 0);
de->d_inode->i_nlink--;
unlock_kernel();
return 0;
}
......
......@@ -3030,19 +3030,30 @@ static int devfs_unlink (struct inode *dir, struct dentry *dentry)
struct inode *inode = dentry->d_inode;
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
lock_kernel();
de = get_devfs_entry_from_vfs_inode (inode);
DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
if (de == NULL) return -ENOENT;
if (!de->vfs_deletable) return -EPERM;
if (de == NULL) {
unlock_kernel();
return -ENOENT;
}
if (!de->vfs_deletable) {
unlock_kernel();
return -EPERM;
}
write_lock (&de->parent->u.dir.lock);
unhooked = _devfs_unhook (de);
write_unlock (&de->parent->u.dir.lock);
if (!unhooked) return -ENOENT;
if (!unhooked) {
unlock_kernel();
return -ENOENT;
}
if ( !is_devfsd_or_child (fs_info) )
devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
inode->i_uid, inode->i_gid, fs_info, 0);
free_dentry (de);
devfs_put (de);
unlock_kernel();
return 0;
} /* End Function devfs_unlink */
......
......@@ -180,7 +180,9 @@ static int driverfs_unlink(struct inode *dir, struct dentry *dentry)
if (driverfs_empty(dentry)) {
struct inode *inode = dentry->d_inode;
lock_kernel();
inode->i_nlink--;
unlock_kernel();
dput(dentry);
error = 0;
}
......
......@@ -862,9 +862,12 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
struct ext3_dir_entry_2 * de;
handle_t *handle;
lock_kernel();
handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
if (IS_ERR(handle))
if (IS_ERR(handle)) {
unlock_kernel();
return PTR_ERR(handle);
}
if (IS_SYNC(dir))
handle->h_sync = 1;
......@@ -902,6 +905,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
end_unlink:
ext3_journal_stop(handle, dir);
unlock_kernel();
brelse (bh);
return retval;
}
......@@ -1129,7 +1133,7 @@ struct inode_operations ext3_dir_inode_operations = {
create: ext3_create,
lookup: ext3_lookup,
link: ext3_link, /* BKL held */
unlink: ext3_unlink, /* BKL held */
unlink: ext3_unlink,
symlink: ext3_symlink, /* BKL held */
mkdir: ext3_mkdir, /* BKL held */
rmdir: ext3_rmdir, /* BKL held */
......
......@@ -262,12 +262,18 @@ int hfs_unlink(struct inode * dir, struct dentry *dentry)
struct hfs_cat_key key;
int error;
lock_kernel();
entry = HFS_I(dir)->entry;
if (build_key(&key, dir, dentry->d_name.name,
dentry->d_name.len))
dentry->d_name.len)) {
unlock_kernel();
return -EPERM;
}
if (!(victim = hfs_cat_get(entry->mdb, &key)))
if (!(victim = hfs_cat_get(entry->mdb, &key))) {
unlock_kernel();
return -ENOENT;
}
error = -EPERM;
if (victim->type != HFS_CDR_FIL)
......@@ -285,6 +291,7 @@ int hfs_unlink(struct inode * dir, struct dentry *dentry)
hfs_unlink_put:
hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */
unlock_kernel();
return error;
}
......
......@@ -315,11 +315,13 @@ static int dbl_unlink(struct inode * dir, struct dentry *dentry)
{
int error;
lock_kernel();
error = hfs_unlink(dir, dentry);
if ((error == -ENOENT) && is_hdr(dir, dentry->d_name.name,
dentry->d_name.len)) {
error = -EPERM;
}
unlock_kernel();
return error;
}
......
......@@ -369,9 +369,11 @@ static int nat_rmdir(struct inode *parent, struct dentry *dentry)
*/
static int nat_hdr_unlink(struct inode *dir, struct dentry *dentry)
{
struct hfs_cat_entry *entry = HFS_I(dir)->entry;
struct hfs_cat_entry *entry;
int error = 0;
lock_kernel();
entry = HFS_I(dir)->entry;
if (!HFS_SB(dir->i_sb)->s_afpd) {
/* Not in AFPD compatibility mode */
error = -EPERM;
......@@ -396,6 +398,7 @@ static int nat_hdr_unlink(struct inode *dir, struct dentry *dentry)
}
}
}
unlock_kernel();
return error;
}
......
......@@ -313,21 +313,26 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry)
fnode_secno fno;
int r;
int rep = 0;
lock_kernel();
hpfs_adjust_length((char *)name, &len);
again:
again:
hpfs_lock_2inodes(dir, inode);
if (!(de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh))) {
hpfs_unlock_2inodes(dir, inode);
unlock_kernel();
return -ENOENT;
}
if (de->first) {
hpfs_brelse4(&qbh);
hpfs_unlock_2inodes(dir, inode);
unlock_kernel();
return -EPERM;
}
if (de->directory) {
hpfs_brelse4(&qbh);
hpfs_unlock_2inodes(dir, inode);
unlock_kernel();
return -EISDIR;
}
fno = de->fnode;
......@@ -360,7 +365,8 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry)
rep = 1;
goto again;
}
ret:
ret:
unlock_kernel();
return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
}
......
......@@ -912,12 +912,14 @@ jffs_unlink(struct inode *dir, struct dentry *dentry)
struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
int ret;
lock_kernel();
D3(printk("***jffs_unlink()\n"));
D3(printk (KERN_NOTICE "unlink(): down biglock\n"));
down(&c->fmc->biglock);
ret = jffs_remove(dir, dentry, 0);
D3(printk (KERN_NOTICE "unlink(): up biglock\n"));
up(&c->fmc->biglock);
unlock_kernel();
return ret;
}
......
......@@ -425,7 +425,11 @@ static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int renam
static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
{
return jffs2_do_unlink(dir_i, dentry, 0);
int res;
lock_kernel();
res = jffs2_do_unlink(dir_i, dentry, 0);
unlock_kernel();
return res;
}
/***********************************************************************/
......
......@@ -11,13 +11,17 @@
static inline void inc_count(struct inode *inode)
{
lock_kernel();
inode->i_nlink++;
unlock_kernel();
mark_inode_dirty(inode);
}
static inline void dec_count(struct inode *inode)
{
lock_kernel();
inode->i_nlink--;
unlock_kernel();
mark_inode_dirty(inode);
}
......@@ -67,17 +71,13 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
if (dentry->d_name.len > dir->i_sb->u.minix_sb.s_namelen)
return ERR_PTR(-ENAMETOOLONG);
lock_kernel();
ino = minix_inode_by_name(dentry);
if (ino) {
inode = iget(dir->i_sb, ino);
if (!inode) {
unlock_kernel();
if (!inode)
return ERR_PTR(-EACCES);
}
}
unlock_kernel();
d_add(dentry, inode);
return NULL;
}
......@@ -91,9 +91,7 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int
inode->i_mode = mode;
minix_set_inode(inode, rdev);
mark_inode_dirty(inode);
lock_kernel();
error = add_nondir(dentry, inode);
unlock_kernel();
}
return error;
}
......@@ -266,8 +264,11 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
inc_count(old_inode);
minix_set_link(new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME;
if (dir_de)
if (dir_de) {
lock_kernel();
new_inode->i_nlink--;
unlock_kernel();
}
dec_count(new_inode);
} else {
if (dir_de) {
......
......@@ -424,6 +424,7 @@ int msdos_unlink( struct inode *dir, struct dentry *dentry)
struct msdos_dir_entry *de;
bh = NULL;
lock_kernel();
res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
&bh, &de, &ino);
if (res < 0)
......@@ -439,6 +440,7 @@ int msdos_unlink( struct inode *dir, struct dentry *dentry)
mark_inode_dirty(dir);
res = 0;
unlink_done:
unlock_kernel();
return res;
}
......
......@@ -1486,9 +1486,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
if (d_mountpoint(dentry))
error = -EBUSY;
else {
lock_kernel();
error = dir->i_op->unlink(dir, dentry);
unlock_kernel();
if (!error)
d_delete(dentry);
}
......
......@@ -958,9 +958,11 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
static int ncp_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(dir);
struct ncp_server *server;
int error;
lock_kernel();
server = NCP_SERVER(dir);
DPRINTK("ncp_unlink: unlinking %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
......@@ -1011,6 +1013,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
}
out:
unlock_kernel();
return error;
}
......
......@@ -871,6 +871,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name);
lock_kernel();
error = nfs_sillyrename(dir, dentry);
if (error && error != -EBUSY) {
error = nfs_safe_remove(dentry);
......@@ -878,6 +879,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
nfs_renew_times(dentry);
}
}
unlock_kernel();
return error;
}
......
......@@ -871,6 +871,7 @@ static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
name = dentry->d_name.name;
len = dentry->d_name.len;
lock_kernel();
for (i = 0; i < aliases_nodes; i++)
if ((strlen (alias_names [i]) == len)
&& !strncmp (name, alias_names[i], len)) {
......@@ -884,6 +885,7 @@ static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
buffer [10 + len] = 0;
prom_feval (buffer);
}
unlock_kernel();
return 0;
}
......
......@@ -205,9 +205,11 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry)
int ino;
QNX4DEBUG(("qnx4: qnx4_unlink [%s]\n", dentry->d_name.name));
lock_kernel();
bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name,
&de, &ino);
if (bh == NULL) {
unlock_kernel();
return -ENOENT;
}
inode = dentry->d_inode;
......@@ -233,7 +235,8 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry)
mark_inode_dirty(inode);
retval = 0;
end_unlink:
end_unlink:
unlock_kernel();
brelse(bh);
return retval;
......
......@@ -29,6 +29,7 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
......@@ -219,7 +220,9 @@ static int ramfs_unlink(struct inode * dir, struct dentry *dentry)
if (ramfs_empty(dentry)) {
struct inode *inode = dentry->d_inode;
lock_kernel();
inode->i_nlink--;
unlock_kernel();
dput(dentry); /* Undo the count from "create" - this does all the work */
retval = 0;
}
......
......@@ -817,6 +817,7 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
two stat datas */
jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;
lock_kernel();
journal_begin(&th, dir->i_sb, jbegin_count) ;
windex = push_journal_writer("reiserfs_unlink") ;
......@@ -865,6 +866,7 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
pop_journal_writer(windex) ;
journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_check_path(&path) ;
unlock_kernel();
return 0;
end_unlink:
......@@ -872,6 +874,7 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
pop_journal_writer(windex) ;
journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_check_path(&path) ;
unlock_kernel();
return retval;
}
......
......@@ -545,12 +545,14 @@ smb_unlink(struct inode *dir, struct dentry *dentry)
/*
* Close the file if it's open.
*/
lock_kernel();
smb_close(dentry->d_inode);
smb_invalid_dir_cache(dir);
error = smb_proc_unlink(dentry);
if (!error)
smb_renew_times(dentry);
unlock_kernel();
return error;
}
......
......@@ -19,13 +19,17 @@
static inline void inc_count(struct inode *inode)
{
lock_kernel();
inode->i_nlink++;
unlock_kernel();
mark_inode_dirty(inode);
}
static inline void dec_count(struct inode *inode)
{
lock_kernel();
inode->i_nlink--;
unlock_kernel();
mark_inode_dirty(inode);
}
......@@ -73,17 +77,13 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
dentry->d_op = dir->i_sb->s_root->d_op;
if (dentry->d_name.len > SYSV_NAMELEN)
return ERR_PTR(-ENAMETOOLONG);
lock_kernel();
ino = sysv_inode_by_name(dentry);
if (ino) {
inode = iget(dir->i_sb, ino);
if (!inode) {
unlock_kernel();
if (!inode)
return ERR_PTR(-EACCES);
}
}
unlock_kernel();
d_add(dentry, inode);
return NULL;
}
......@@ -96,9 +96,7 @@ static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int
if (!IS_ERR(inode)) {
sysv_set_inode(inode, rdev);
mark_inode_dirty(inode);
lock_kernel();
err = add_nondir(dentry, inode);
unlock_kernel();
}
return err;
}
......@@ -274,8 +272,11 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
inc_count(old_inode);
sysv_set_link(new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME;
if (dir_de)
if (dir_de) {
lock_kernel();
new_inode->i_nlink--;
unlock_kernel();
}
dec_count(new_inode);
} else {
if (dir_de) {
......
......@@ -892,6 +892,7 @@ static int udf_unlink(struct inode * dir, struct dentry * dentry)
struct FileIdentDesc cfi;
retval = -ENOENT;
lock_kernel();
fi = udf_find_entry(dir, dentry, &fibh, &cfi);
if (!fi)
goto out;
......@@ -926,6 +927,7 @@ static int udf_unlink(struct inode * dir, struct dentry * dentry)
udf_release_data(fibh.ebh);
udf_release_data(fibh.sbh);
out:
unlock_kernel();
return retval;
}
......
......@@ -228,6 +228,7 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry)
struct ufs_dir_entry * de;
int err = -ENOENT;
lock_kernel();
de = ufs_find_entry (dentry, &bh);
if (!de)
goto out;
......@@ -240,6 +241,7 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry)
ufs_dec_count(inode);
err = 0;
out:
unlock_kernel();
return err;
}
......
......@@ -1112,9 +1112,12 @@ int vfat_unlink(struct inode *dir, struct dentry* dentry)
struct msdos_dir_entry *de;
PRINTK1(("vfat_unlink: %s\n", dentry->d_name.name));
lock_kernel();
res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
if (res < 0)
if (res < 0) {
unlock_kernel();
return res;
}
dentry->d_inode->i_nlink = 0;
dentry->d_inode->i_mtime = CURRENT_TIME;
dentry->d_inode->i_atime = CURRENT_TIME;
......@@ -1122,6 +1125,7 @@ int vfat_unlink(struct inode *dir, struct dentry* dentry)
mark_inode_dirty(dentry->d_inode);
/* releases bh */
vfat_remove_entry(dir,&sinfo,bh,de);
unlock_kernel();
return res;
}
......
......@@ -1069,7 +1069,9 @@ static int shmem_unlink(struct inode * dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
lock_kernel();
inode->i_nlink--;
unlock_kernel();
dput(dentry); /* Undo the count from "create" - this does all the work */
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment