Commit a4dea1b6 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] make hfs use regular semaphores

unrelated to the rest, replaces home-grown (racy) semaphores in fs/hfs
with the real thing.
parent f6daaf1a
...@@ -16,21 +16,6 @@ ...@@ -16,21 +16,6 @@
#include "hfs_btree.h" #include "hfs_btree.h"
/*================ File-local functions ================*/ /*================ File-local functions ================*/
/* btree locking functions */
static inline void hfs_btree_lock(struct hfs_btree *tree)
{
while (tree->lock)
hfs_sleep_on(&tree->wait);
tree->lock = 1;
}
static inline void hfs_btree_unlock(struct hfs_btree *tree)
{
tree->lock = 0;
hfs_wake_up(&tree->wait);
}
/* /*
* binsert_nonfull() * binsert_nonfull()
* *
...@@ -526,11 +511,11 @@ int hfs_binsert(struct hfs_btree *tree, const struct hfs_bkey *key, ...@@ -526,11 +511,11 @@ int hfs_binsert(struct hfs_btree *tree, const struct hfs_bkey *key,
/* make certain we have enough nodes to proceed */ /* make certain we have enough nodes to proceed */
if ((tree->bthFree - tree->reserved) < reserve) { if ((tree->bthFree - tree->reserved) < reserve) {
hfs_brec_relse(&brec, NULL); hfs_brec_relse(&brec, NULL);
hfs_btree_lock(tree); down(&tree->sem);
if ((tree->bthFree - tree->reserved) < reserve) { if ((tree->bthFree - tree->reserved) < reserve) {
hfs_btree_extend(tree); hfs_btree_extend(tree);
} }
hfs_btree_unlock(tree); up(&tree->sem);
if ((tree->bthFree - tree->reserved) < reserve) { if ((tree->bthFree - tree->reserved) < reserve) {
return -ENOSPC; return -ENOSPC;
} else { } else {
......
...@@ -172,8 +172,7 @@ struct hfs_btree * hfs_btree_init(struct hfs_mdb *mdb, ino_t cnid, ...@@ -172,8 +172,7 @@ struct hfs_btree * hfs_btree_init(struct hfs_mdb *mdb, ino_t cnid,
bt->magic = HFS_BTREE_MAGIC; bt->magic = HFS_BTREE_MAGIC;
bt->sys_mdb = mdb->sys_mdb; bt->sys_mdb = mdb->sys_mdb;
bt->reserved = 0; bt->reserved = 0;
bt->lock = 0; sema_init(&bt->sem, 1);
hfs_init_waitqueue(&bt->wait);
bt->dirt = 0; bt->dirt = 0;
memset(bt->cache, 0, sizeof(bt->cache)); memset(bt->cache, 0, sizeof(bt->cache));
......
...@@ -302,8 +302,7 @@ static void __read_entry(struct hfs_cat_entry *entry, ...@@ -302,8 +302,7 @@ static void __read_entry(struct hfs_cat_entry *entry,
entry->modify_date = hfs_get_nl(cat->u.dir.MdDat); entry->modify_date = hfs_get_nl(cat->u.dir.MdDat);
entry->backup_date = hfs_get_nl(cat->u.dir.BkDat); entry->backup_date = hfs_get_nl(cat->u.dir.BkDat);
dir->dirs = dir->files = 0; dir->dirs = dir->files = 0;
hfs_init_waitqueue(&dir->read_wait); init_rwsem(&dir->sem);
hfs_init_waitqueue(&dir->write_wait);
} else if (cat->cdrType == HFS_CDR_FIL) { } else if (cat->cdrType == HFS_CDR_FIL) {
struct hfs_file *fil = &entry->u.file; struct hfs_file *fil = &entry->u.file;
...@@ -641,51 +640,6 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir, ...@@ -641,51 +640,6 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir,
hfs_cat_mark_dirty(dir); hfs_cat_mark_dirty(dir);
} }
/*
* Add a writer to dir, excluding readers.
*
* XXX: this is wrong. it allows a move to occur when a directory
* is being written to.
*/
static inline void start_write(struct hfs_cat_entry *dir)
{
if (dir->u.dir.readers || waitqueue_active(&dir->u.dir.read_wait)) {
hfs_sleep_on(&dir->u.dir.write_wait);
}
++dir->u.dir.writers;
}
/*
* Add a reader to dir, excluding writers.
*/
static inline void start_read(struct hfs_cat_entry *dir)
{
if (dir->u.dir.writers || waitqueue_active(&dir->u.dir.write_wait)) {
hfs_sleep_on(&dir->u.dir.read_wait);
}
++dir->u.dir.readers;
}
/*
* Remove a writer from dir, possibly admitting readers.
*/
static inline void end_write(struct hfs_cat_entry *dir)
{
if (!(--dir->u.dir.writers)) {
hfs_wake_up(&dir->u.dir.read_wait);
}
}
/*
* Remove a reader from dir, possibly admitting writers.
*/
static inline void end_read(struct hfs_cat_entry *dir)
{
if (!(--dir->u.dir.readers)) {
hfs_wake_up(&dir->u.dir.write_wait);
}
}
/* /*
* create_entry() * create_entry()
* *
...@@ -707,7 +661,7 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key, ...@@ -707,7 +661,7 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
} }
/* keep readers from getting confused by changing dir size */ /* keep readers from getting confused by changing dir size */
start_write(parent); down_write(&parent->u.dir.sem);
/* create a locked entry in the cache */ /* create a locked entry in the cache */
entry = get_entry(mdb, key, 0); entry = get_entry(mdb, key, 0);
...@@ -782,7 +736,7 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key, ...@@ -782,7 +736,7 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
bail2: bail2:
hfs_cat_put(entry); hfs_cat_put(entry);
done: done:
end_write(parent); up_write(&parent->u.dir.sem);
return error; return error;
} }
...@@ -1058,21 +1012,19 @@ int hfs_cat_open(struct hfs_cat_entry *dir, struct hfs_brec *brec) ...@@ -1058,21 +1012,19 @@ int hfs_cat_open(struct hfs_cat_entry *dir, struct hfs_brec *brec)
struct hfs_cat_key key; struct hfs_cat_key key;
int error; int error;
if (dir->type != HFS_CDR_DIR) { if (dir->type != HFS_CDR_DIR)
return -EINVAL; return -EINVAL;
}
/* Block writers */ /* Block writers */
start_read(dir); down_read(&dir->u.dir.sem);
/* Find the directory */ /* Find the directory */
hfs_cat_build_key(dir->cnid, NULL, &key); hfs_cat_build_key(dir->cnid, NULL, &key);
error = hfs_bfind(brec, dir->mdb->cat_tree, error = hfs_bfind(brec, dir->mdb->cat_tree,
HFS_BKEY(&key), HFS_BFIND_READ_EQ); HFS_BKEY(&key), HFS_BFIND_READ_EQ);
if (error) { if (error)
end_read(dir); up_read(&dir->u.dir.sem);
}
return error; return error;
} }
...@@ -1109,7 +1061,7 @@ int hfs_cat_next(struct hfs_cat_entry *dir, struct hfs_brec *brec, ...@@ -1109,7 +1061,7 @@ int hfs_cat_next(struct hfs_cat_entry *dir, struct hfs_brec *brec,
*type = ((struct hfs_cat_rec *)brec->data)->cdrType; *type = ((struct hfs_cat_rec *)brec->data)->cdrType;
*cnid = brec_to_id(brec); *cnid = brec_to_id(brec);
} else { } else {
end_read(dir); up_read(&dir->u.dir.sem);
} }
return error; return error;
} }
...@@ -1127,7 +1079,7 @@ void hfs_cat_close(struct hfs_cat_entry *dir, struct hfs_brec *brec) ...@@ -1127,7 +1079,7 @@ void hfs_cat_close(struct hfs_cat_entry *dir, struct hfs_brec *brec)
{ {
if (dir && brec) { if (dir && brec) {
hfs_brec_relse(brec, NULL); hfs_brec_relse(brec, NULL);
end_read(dir); up_read(&dir->u.dir.sem);
} }
} }
...@@ -1260,11 +1212,11 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, ...@@ -1260,11 +1212,11 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
} }
/* keep readers from getting confused by changing dir size */ /* keep readers from getting confused by changing dir size */
start_write(parent); down_write(&parent->u.dir.sem);
/* don't delete a busy directory */ /* don't delete a busy directory */
if (entry->type == HFS_CDR_DIR) { if (entry->type == HFS_CDR_DIR) {
start_read(entry); down_read(&entry->u.dir.sem);
error = -ENOTEMPTY; error = -ENOTEMPTY;
if (entry->u.dir.files || entry->u.dir.dirs) if (entry->u.dir.files || entry->u.dir.dirs)
...@@ -1299,10 +1251,9 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, ...@@ -1299,10 +1251,9 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
unlock_entry(entry); unlock_entry(entry);
hfs_delete_end: hfs_delete_end:
if (entry->type == HFS_CDR_DIR) { if (entry->type == HFS_CDR_DIR)
end_read(entry); up_read(&entry->u.dir.sem);
} up_write(&parent->u.dir.sem);
end_write(parent);
return error; return error;
} }
...@@ -1347,10 +1298,10 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir, ...@@ -1347,10 +1298,10 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,
} }
/* keep readers from getting confused by changing dir size */ /* keep readers from getting confused by changing dir size */
start_write(new_dir); down_write(&new_dir->u.dir.sem);
if (old_dir != new_dir) { /* AV: smells like a deadlock */
start_write(old_dir); if (old_dir != new_dir)
} down_write(&old_dir->u.dir.sem);
/* Don't move a directory inside itself */ /* Don't move a directory inside itself */
if (is_dir) { if (is_dir) {
...@@ -1556,10 +1507,9 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir, ...@@ -1556,10 +1507,9 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,
hfs_cat_put(dest); hfs_cat_put(dest);
} }
done: done:
if (new_dir != old_dir) { if (new_dir != old_dir)
end_write(old_dir); up_write(&old_dir->u.dir.sem);
} up_write(&new_dir->u.dir.sem);
end_write(new_dir);
return error; return error;
} }
......
...@@ -310,10 +310,7 @@ struct hfs_dir { ...@@ -310,10 +310,7 @@ struct hfs_dir {
hfs_u16 flags; hfs_u16 flags;
hfs_u16 dirs; /* Number of directories in this one */ hfs_u16 dirs; /* Number of directories in this one */
hfs_u16 files; /* Number of files in this directory */ hfs_u16 files; /* Number of files in this directory */
int readers; struct rw_semaphore sem;
hfs_wait_queue read_wait;
int writers;
hfs_wait_queue write_wait;
}; };
/* /*
......
...@@ -194,8 +194,7 @@ struct hfs_btree { ...@@ -194,8 +194,7 @@ struct hfs_btree {
struct hfs_bnode /* The bnode cache */ struct hfs_bnode /* The bnode cache */
*cache[HFS_CACHELEN]; *cache[HFS_CACHELEN];
struct hfs_cat_entry entry; /* Fake catalog entry */ struct hfs_cat_entry entry; /* Fake catalog entry */
int lock; struct semaphore sem;
hfs_wait_queue wait;
int dirt; int dirt;
int keySize; int keySize;
/* Fields from the BTHdrRec in native byte-order: */ /* Fields from the BTHdrRec in native byte-order: */
......
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