diff options
author | Christoph Hellwig <hch@tuxera.com> | 2010-10-01 05:45:08 +0200 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2010-10-01 05:45:08 +0200 |
commit | 7ac9fb9c2a50963b699b3548e6f00698c1554dc6 (patch) | |
tree | 3660bfb2985c65838b5969694e54043ae6639b3a /fs/hfsplus/dir.c | |
parent | 58a818f532e83f337689358c102ba2048d1b37f5 (diff) |
hfsplus: add per-superblock lock for volume header updates
Lock updates to the mutal fields in the volume header, and document the
locing in the hfsplus_sb_info structure.
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Diffstat (limited to 'fs/hfsplus/dir.c')
-rw-r--r-- | fs/hfsplus/dir.c | 54 |
1 files changed, 35 insertions, 19 deletions
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index f8ae468f4ab..1c81eedcab0 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -251,6 +251,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, if (HFSPLUS_IS_RSRC(inode)) return -EPERM; + mutex_lock(&sbi->vh_mutex); if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) { for (;;) { get_random_bytes(&id, sizeof(cnid)); @@ -263,7 +264,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, if (!res) break; if (res != -EEXIST) - return res; + goto out; } HFSPLUS_I(inode)->dev = id; cnid = sbi->next_cnid++; @@ -271,13 +272,13 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); if (res) /* panic? */ - return res; + goto out; sbi->file_count++; } cnid = sbi->next_cnid++; res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode); if (res) - return res; + goto out; inc_nlink(inode); hfsplus_instantiate(dst_dentry, inode, cnid); @@ -286,8 +287,9 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, mark_inode_dirty(inode); sbi->file_count++; dst_dir->i_sb->s_dirt = 1; - - return 0; +out: + mutex_unlock(&sbi->vh_mutex); + return res; } static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) @@ -302,6 +304,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) if (HFSPLUS_IS_RSRC(inode)) return -EPERM; + mutex_lock(&sbi->vh_mutex); cnid = (u32)(unsigned long)dentry->d_fsdata; if (inode->i_ino == cnid && atomic_read(&HFSPLUS_I(inode)->opencnt)) { @@ -312,11 +315,11 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) sbi->hidden_dir, &str); if (!res) inode->i_flags |= S_DEAD; - return res; + goto out; } res = hfsplus_delete_cat(cnid, dir, &dentry->d_name); if (res) - return res; + goto out; if (inode->i_nlink > 0) drop_nlink(inode); @@ -339,37 +342,44 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) sbi->file_count--; inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - +out: + mutex_unlock(&sbi->vh_mutex); return res; } static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode; + struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); + struct inode *inode = dentry->d_inode; int res; - inode = dentry->d_inode; if (inode->i_size != 2) return -ENOTEMPTY; + + mutex_lock(&sbi->vh_mutex); res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); if (res) - return res; + goto out; clear_nlink(inode); inode->i_ctime = CURRENT_TIME_SEC; hfsplus_delete_inode(inode); mark_inode_dirty(inode); - return 0; +out: + mutex_unlock(&sbi->vh_mutex); + return res; } static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { + struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); struct inode *inode; - int res; + int res = -ENOSPC; + mutex_lock(&sbi->vh_mutex); inode = hfsplus_new_inode(dir->i_sb, S_IFLNK | S_IRWXUGO); if (!inode) - return -ENOSPC; + goto out; res = page_symlink(inode, symname, strlen(symname) + 1); if (res) @@ -381,31 +391,35 @@ static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, hfsplus_instantiate(dentry, inode, inode->i_ino); mark_inode_dirty(inode); - return 0; + goto out; out_err: inode->i_nlink = 0; hfsplus_delete_inode(inode); iput(inode); +out: + mutex_unlock(&sbi->vh_mutex); return res; } static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { + struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); struct inode *inode; - int res; + int res = -ENOSPC; + mutex_lock(&sbi->vh_mutex); inode = hfsplus_new_inode(dir->i_sb, mode); if (!inode) - return -ENOSPC; + goto out; res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); if (res) { inode->i_nlink = 0; hfsplus_delete_inode(inode); iput(inode); - return res; + goto out; } if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) @@ -413,7 +427,9 @@ static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, hfsplus_instantiate(dentry, inode, inode->i_ino); mark_inode_dirty(inode); - return 0; +out: + mutex_unlock(&sbi->vh_mutex); + return res; } static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode, |