Commit 9c96c8be authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] hpfs: fix locking scheme

	Fixed the locking scheme.  The need of extra locking was caused by
the fact that hpfs_write_inode() must update directory entry; since HPFS
directories are implemented as b-trees, we must provide protection both
against rename() (to make sure that we update the entry in right directory)
and against rebalancing of the parent.

	Old scheme had both deadlocks and races - to start with, we had no
protection against rename()/unlink()/rmdir(), since (a) locking parent
was done without any warranties that it will remain our parent and (b)
check that we still have a directory entry (== have positive nlink) was
done before we tried to lock the parent.  Moreover, iget serialization
killed two steps ago gave immediate deadlocks if iget() of parent had
triggered another hpfs_write_inode().

	New scheme introduces another per-inode semaphore (hpfs-only,
obviously) protecting the reference to parent.  It's taken on
rename/rmdir/unlink victims and inode being moved by rename.  Old semaphores
are taken only on parent(s) and only after we grab one(s) of the new kind.
hpfs_write_inode() gets the new semaphore on our inode, checks nlink and
if it's non-zero grabs parent and takes the old semaphore on it.

	Order among the semaphores of the same kind is arbitrary - the only
function that might take more than one of the same kind is hpfs_rename()
and it's serialized by VFS.

	We might get away with only one semaphore, but then the ordering
issues would bite us big way - we would have to make sure that child is
always locked before parent (hpfs_write_inode() leaves no other choice)
and while that's easy to do for almost all operations, rename() is a bitch -
as always.  And per-superblock rwsem giving rename() vs. write_inode()
exclusion on hpfs would make the entire thing too baroque for my taste.
	->readdir() takes no locks at all (protection against directory
modifications is provided by VFS exclusion), ditto for ->lookup().
	->llseek() on directories switched to use of (VFS) ->i_sem, so
it's safe from directory modifications and ->readdir() is safe from it -
no hpfs locks are needed here.
parent d9013aae
...@@ -26,22 +26,6 @@ void hpfs_unlock_creation(struct super_block *s) ...@@ -26,22 +26,6 @@ void hpfs_unlock_creation(struct super_block *s)
up(&hpfs_sb(s)->hpfs_creation_de); up(&hpfs_sb(s)->hpfs_creation_de);
} }
void hpfs_lock_inode(struct inode *i)
{
if (i) {
struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
down(&hpfs_inode->i_sem);
}
}
void hpfs_unlock_inode(struct inode *i)
{
if (i) {
struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
up(&hpfs_inode->i_sem);
}
}
/* Map a sector into a buffer and return pointers to it and to the buffer. */ /* Map a sector into a buffer and return pointers to it and to the buffer. */
void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp, void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp,
......
...@@ -35,19 +35,19 @@ loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) ...@@ -35,19 +35,19 @@ loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
/*printk("dir lseek\n");*/ /*printk("dir lseek\n");*/
if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok; if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
hpfs_lock_inode(i); down(&i->i_sem);
pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1; pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
while (pos != new_off) { while (pos != new_off) {
if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh); if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
else goto fail; else goto fail;
if (pos == 12) goto fail; if (pos == 12) goto fail;
} }
hpfs_unlock_inode(i); up(&i->i_sem);
ok: ok:
unlock_kernel(); unlock_kernel();
return filp->f_pos = new_off; return filp->f_pos = new_off;
fail: fail:
hpfs_unlock_inode(i); up(&i->i_sem);
/*printk("illegal lseek: %016llx\n", new_off);*/ /*printk("illegal lseek: %016llx\n", new_off);*/
unlock_kernel(); unlock_kernel();
return -ESPIPE; return -ESPIPE;
...@@ -109,8 +109,6 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -109,8 +109,6 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto out; goto out;
} }
hpfs_lock_inode(inode);
while (1) { while (1) {
again: again:
/* This won't work when cycle is longer than number of dirents /* This won't work when cycle is longer than number of dirents
...@@ -118,31 +116,23 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -118,31 +116,23 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
maybe killall -9 ls helps */ maybe killall -9 ls helps */
if (hpfs_sb(inode->i_sb)->sb_chk) if (hpfs_sb(inode->i_sb)->sb_chk)
if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) { if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) {
hpfs_unlock_inode(inode);
ret = -EFSERROR; ret = -EFSERROR;
goto out; goto out;
} }
if (filp->f_pos == 12) { if (filp->f_pos == 12)
hpfs_unlock_inode(inode);
goto out; goto out;
}
if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) { if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) {
printk("HPFS: warning: pos==%d\n",(int)filp->f_pos); printk("HPFS: warning: pos==%d\n",(int)filp->f_pos);
hpfs_unlock_inode(inode);
goto out; goto out;
} }
if (filp->f_pos == 0) { if (filp->f_pos == 0) {
if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) { if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
hpfs_unlock_inode(inode);
goto out; goto out;
}
filp->f_pos = 11; filp->f_pos = 11;
} }
if (filp->f_pos == 11) { if (filp->f_pos == 11) {
if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0) { if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0)
hpfs_unlock_inode(inode);
goto out; goto out;
}
filp->f_pos = 1; filp->f_pos = 1;
} }
if (filp->f_pos == 1) { if (filp->f_pos == 1) {
...@@ -151,13 +141,11 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -151,13 +141,11 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
filp->f_version = inode->i_version; filp->f_version = inode->i_version;
} }
/*if (filp->f_version != inode->i_version) { /*if (filp->f_version != inode->i_version) {
hpfs_unlock_inode(inode);
ret = -ENOENT; ret = -ENOENT;
goto out; goto out;
}*/ }*/
old_pos = filp->f_pos; old_pos = filp->f_pos;
if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) { if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
hpfs_unlock_inode(inode);
ret = -EIOERROR; ret = -EIOERROR;
goto out; goto out;
} }
...@@ -174,7 +162,6 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -174,7 +162,6 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
filp->f_pos = old_pos; filp->f_pos = old_pos;
if (tempname != (char *)de->name) kfree(tempname); if (tempname != (char *)de->name) kfree(tempname);
hpfs_brelse4(&qbh); hpfs_brelse4(&qbh);
hpfs_unlock_inode(inode);
goto out; goto out;
} }
if (tempname != (char *)de->name) kfree(tempname); if (tempname != (char *)de->name) kfree(tempname);
...@@ -220,7 +207,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name ...@@ -220,7 +207,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
goto end_add; goto end_add;
} }
hpfs_lock_inode(dir);
/* /*
* '.' and '..' will never be passed here. * '.' and '..' will never be passed here.
*/ */
...@@ -312,7 +298,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name ...@@ -312,7 +298,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
*/ */
end: end:
hpfs_unlock_inode(dir);
end_add: end_add:
hpfs_set_dentry_operations(dentry); hpfs_set_dentry_operations(dentry);
unlock_kernel(); unlock_kernel();
...@@ -328,7 +313,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name ...@@ -328,7 +313,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
/*bail:*/ /*bail:*/
hpfs_unlock_inode(dir);
unlock_kernel(); unlock_kernel();
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
...@@ -15,17 +15,6 @@ ...@@ -15,17 +15,6 @@
#define BLOCKS(size) (((size) + 511) >> 9) #define BLOCKS(size) (((size) + 511) >> 9)
/* HUH? */
int hpfs_open(struct inode *i, struct file *f)
{
lock_kernel();
hpfs_lock_inode(i);
hpfs_unlock_inode(i); /* make sure nobody is deleting the file */
unlock_kernel();
if (!i->i_nlink) return -ENOENT;
return 0;
}
int hpfs_file_release(struct inode *inode, struct file *file) int hpfs_file_release(struct inode *inode, struct file *file)
{ {
lock_kernel(); lock_kernel();
......
...@@ -192,8 +192,6 @@ void hpfs_remove_fnode(struct super_block *, fnode_secno fno); ...@@ -192,8 +192,6 @@ void hpfs_remove_fnode(struct super_block *, fnode_secno fno);
void hpfs_lock_creation(struct super_block *); void hpfs_lock_creation(struct super_block *);
void hpfs_unlock_creation(struct super_block *); void hpfs_unlock_creation(struct super_block *);
void hpfs_lock_inode(struct inode *);
void hpfs_unlock_inode(struct inode *);
void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int); void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int);
void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **); void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **);
void *hpfs_map_4sectors(struct super_block *, unsigned, struct quad_buffer_head *, int); void *hpfs_map_4sectors(struct super_block *, unsigned, struct quad_buffer_head *, int);
......
...@@ -229,13 +229,17 @@ void hpfs_write_inode(struct inode *i) ...@@ -229,13 +229,17 @@ void hpfs_write_inode(struct inode *i)
{ {
struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
struct inode *parent; struct inode *parent;
if (!i->i_nlink) return;
if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return; if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return;
if (hpfs_inode->i_rddir_off && !atomic_read(&i->i_count)) { if (hpfs_inode->i_rddir_off && !atomic_read(&i->i_count)) {
if (*hpfs_inode->i_rddir_off) printk("HPFS: write_inode: some position still there\n"); if (*hpfs_inode->i_rddir_off) printk("HPFS: write_inode: some position still there\n");
kfree(hpfs_inode->i_rddir_off); kfree(hpfs_inode->i_rddir_off);
hpfs_inode->i_rddir_off = NULL; hpfs_inode->i_rddir_off = NULL;
} }
down(&hpfs_inode->i_parent);
if (!i->i_nlink) {
up(&hpfs_inode->i_parent);
return;
}
parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir); parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir);
if (parent) { if (parent) {
hpfs_inode->i_dirty = 0; hpfs_inode->i_dirty = 0;
...@@ -244,13 +248,14 @@ void hpfs_write_inode(struct inode *i) ...@@ -244,13 +248,14 @@ void hpfs_write_inode(struct inode *i)
hpfs_read_inode(parent); hpfs_read_inode(parent);
unlock_new_inode(parent); unlock_new_inode(parent);
} }
hpfs_lock_inode(parent); down(&hpfs_inode->i_sem);
hpfs_write_inode_nolock(i); hpfs_write_inode_nolock(i);
hpfs_unlock_inode(parent); up(&hpfs_inode->i_sem);
iput(parent); iput(parent);
} else { } else {
mark_inode_dirty(i); mark_inode_dirty(i);
} }
up(&hpfs_inode->i_parent);
} }
void hpfs_write_inode_nolock(struct inode *i) void hpfs_write_inode_nolock(struct inode *i)
......
...@@ -63,7 +63,7 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -63,7 +63,7 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (dee.read_only) if (dee.read_only)
result->i_mode &= ~0222; result->i_mode &= ~0222;
hpfs_lock_inode(dir); down(&hpfs_i(dir)->i_sem);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1) if (r == 1)
goto bail3; goto bail3;
...@@ -104,11 +104,11 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -104,11 +104,11 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
hpfs_write_inode_nolock(result); hpfs_write_inode_nolock(result);
} }
d_instantiate(dentry, result); d_instantiate(dentry, result);
hpfs_unlock_inode(dir); up(&hpfs_i(dir)->i_sem);
unlock_kernel(); unlock_kernel();
return 0; return 0;
bail3: bail3:
hpfs_unlock_inode(dir); up(&hpfs_i(dir)->i_sem);
iput(result); iput(result);
bail2: bail2:
hpfs_brelse4(&qbh0); hpfs_brelse4(&qbh0);
...@@ -171,7 +171,7 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct namei ...@@ -171,7 +171,7 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct namei
result->i_data.a_ops = &hpfs_aops; result->i_data.a_ops = &hpfs_aops;
hpfs_i(result)->mmu_private = 0; hpfs_i(result)->mmu_private = 0;
hpfs_lock_inode(dir); down(&hpfs_i(dir)->i_sem);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1) if (r == 1)
goto bail2; goto bail2;
...@@ -196,12 +196,12 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct namei ...@@ -196,12 +196,12 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct namei
hpfs_write_inode_nolock(result); hpfs_write_inode_nolock(result);
} }
d_instantiate(dentry, result); d_instantiate(dentry, result);
hpfs_unlock_inode(dir); up(&hpfs_i(dir)->i_sem);
unlock_kernel(); unlock_kernel();
return 0; return 0;
bail2: bail2:
hpfs_unlock_inode(dir); up(&hpfs_i(dir)->i_sem);
iput(result); iput(result);
bail1: bail1:
brelse(bh); brelse(bh);
...@@ -257,7 +257,7 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) ...@@ -257,7 +257,7 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
result->i_blocks = 1; result->i_blocks = 1;
init_special_inode(result, mode, rdev); init_special_inode(result, mode, rdev);
hpfs_lock_inode(dir); down(&hpfs_i(dir)->i_sem);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1) if (r == 1)
goto bail2; goto bail2;
...@@ -274,12 +274,12 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) ...@@ -274,12 +274,12 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
hpfs_write_inode_nolock(result); hpfs_write_inode_nolock(result);
d_instantiate(dentry, result); d_instantiate(dentry, result);
hpfs_unlock_inode(dir); up(&hpfs_i(dir)->i_sem);
brelse(bh); brelse(bh);
unlock_kernel(); unlock_kernel();
return 0; return 0;
bail2: bail2:
hpfs_unlock_inode(dir); up(&hpfs_i(dir)->i_sem);
iput(result); iput(result);
bail1: bail1:
brelse(bh); brelse(bh);
...@@ -338,7 +338,7 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) ...@@ -338,7 +338,7 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
result->i_op = &page_symlink_inode_operations; result->i_op = &page_symlink_inode_operations;
result->i_data.a_ops = &hpfs_symlink_aops; result->i_data.a_ops = &hpfs_symlink_aops;
hpfs_lock_inode(dir); down(&hpfs_i(dir)->i_sem);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
if (r == 1) if (r == 1)
goto bail2; goto bail2;
...@@ -357,11 +357,11 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) ...@@ -357,11 +357,11 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
hpfs_write_inode_nolock(result); hpfs_write_inode_nolock(result);
d_instantiate(dentry, result); d_instantiate(dentry, result);
hpfs_unlock_inode(dir); up(&hpfs_i(dir)->i_sem);
unlock_kernel(); unlock_kernel();
return 0; return 0;
bail2: bail2:
hpfs_unlock_inode(dir); up(&hpfs_i(dir)->i_sem);
iput(result); iput(result);
bail1: bail1:
brelse(bh); brelse(bh);
...@@ -387,8 +387,8 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -387,8 +387,8 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry)
lock_kernel(); lock_kernel();
hpfs_adjust_length((char *)name, &len); hpfs_adjust_length((char *)name, &len);
again: again:
hpfs_lock_inode(dir); down(&hpfs_i(inode)->i_parent);
hpfs_lock_inode(inode); down(&hpfs_i(dir)->i_sem);
err = -ENOENT; err = -ENOENT;
de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh);
if (!de) if (!de)
...@@ -415,8 +415,8 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -415,8 +415,8 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry)
if (rep++) if (rep++)
break; break;
hpfs_unlock_inode(inode); up(&hpfs_i(dir)->i_sem);
hpfs_unlock_inode(dir); up(&hpfs_i(inode)->i_parent);
d_drop(dentry); d_drop(dentry);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
if (atomic_read(&dentry->d_count) > 1 || if (atomic_read(&dentry->d_count) > 1 ||
...@@ -447,8 +447,8 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -447,8 +447,8 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry)
out1: out1:
hpfs_brelse4(&qbh); hpfs_brelse4(&qbh);
out: out:
hpfs_unlock_inode(inode); up(&hpfs_i(dir)->i_sem);
hpfs_unlock_inode(dir); up(&hpfs_i(inode)->i_parent);
unlock_kernel(); unlock_kernel();
return err; return err;
} }
...@@ -468,8 +468,8 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -468,8 +468,8 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
hpfs_adjust_length((char *)name, &len); hpfs_adjust_length((char *)name, &len);
lock_kernel(); lock_kernel();
hpfs_lock_inode(dir); down(&hpfs_i(inode)->i_parent);
hpfs_lock_inode(inode); down(&hpfs_i(dir)->i_sem);
err = -ENOENT; err = -ENOENT;
de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh);
if (!de) if (!de)
...@@ -507,8 +507,8 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -507,8 +507,8 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
out1: out1:
hpfs_brelse4(&qbh); hpfs_brelse4(&qbh);
out: out:
hpfs_unlock_inode(inode); up(&hpfs_i(dir)->i_sem);
hpfs_unlock_inode(dir); up(&hpfs_i(inode)->i_parent);
unlock_kernel(); unlock_kernel();
return err; return err;
} }
...@@ -565,10 +565,13 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -565,10 +565,13 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
hpfs_adjust_length((char *)old_name, &old_len); hpfs_adjust_length((char *)old_name, &old_len);
lock_kernel(); lock_kernel();
hpfs_lock_inode(old_dir); /* order doesn't matter, due to VFS exclusion */
down(&hpfs_i(i)->i_parent);
if (new_inode)
down(&hpfs_i(new_inode)->i_parent);
down(&hpfs_i(old_dir)->i_sem);
if (new_dir != old_dir) if (new_dir != old_dir)
hpfs_lock_inode(new_dir); down(&hpfs_i(new_dir)->i_sem);
hpfs_lock_inode(i);
/* Erm? Moving over the empty non-busy directory is perfectly legal */ /* Erm? Moving over the empty non-busy directory is perfectly legal */
if (new_inode && S_ISDIR(new_inode->i_mode)) { if (new_inode && S_ISDIR(new_inode->i_mode)) {
...@@ -646,11 +649,13 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -646,11 +649,13 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv; hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv;
hpfs_decide_conv(i, (char *)new_name, new_len); hpfs_decide_conv(i, (char *)new_name, new_len);
end1: end1:
hpfs_unlock_inode(i);
if (old_dir != new_dir) if (old_dir != new_dir)
hpfs_unlock_inode(new_dir); up(&hpfs_i(new_dir)->i_sem);
hpfs_unlock_inode(old_dir); up(&hpfs_i(old_dir)->i_sem);
up(&hpfs_i(i)->i_parent);
if (new_inode)
up(&hpfs_i(new_inode)->i_parent);
unlock_kernel(); unlock_kernel();
return err; return err;
} }
...@@ -184,6 +184,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) ...@@ -184,6 +184,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) { SLAB_CTOR_CONSTRUCTOR) {
init_MUTEX(&ei->i_sem); init_MUTEX(&ei->i_sem);
init_MUTEX(&ei->i_parent);
inode_init_once(&ei->vfs_inode); inode_init_once(&ei->vfs_inode);
} }
} }
......
...@@ -16,7 +16,8 @@ struct hpfs_inode_info { ...@@ -16,7 +16,8 @@ struct hpfs_inode_info {
unsigned i_ea_uid : 1; /* file's uid is stored in ea */ unsigned i_ea_uid : 1; /* file's uid is stored in ea */
unsigned i_ea_gid : 1; /* file's gid is stored in ea */ unsigned i_ea_gid : 1; /* file's gid is stored in ea */
unsigned i_dirty : 1; unsigned i_dirty : 1;
struct semaphore i_sem; /* semaphore */ struct semaphore i_sem;
struct semaphore i_parent;
loff_t **i_rddir_off; loff_t **i_rddir_off;
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
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