hfs: switch to ->iterate_shared()
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 13 May 2016 00:13:50 +0000 (20:13 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 13 May 2016 00:13:50 +0000 (20:13 -0400)
exact parallel of hfsplus analogue

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/hfs/catalog.c
fs/hfs/dir.c
fs/hfs/hfs_fs.h
fs/hfs/inode.c

index 1eb5d415d4346c460f715c90f2127da40830b8fb..98cde8ba5dc2659c2c38bda2eb89f9245681654d 100644 (file)
@@ -240,10 +240,13 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
                }
        }
 
+       /* we only need to take spinlock for exclusion with ->release() */
+       spin_lock(&HFS_I(dir)->open_dir_lock);
        list_for_each_entry(rd, &HFS_I(dir)->open_dir_list, list) {
                if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
                        rd->file->f_pos--;
        }
+       spin_unlock(&HFS_I(dir)->open_dir_lock);
 
        res = hfs_brec_remove(&fd);
        if (res)
index e9f2b855f83160d3798e4ef62f6d86a7f0e69547..163190ecc0d2e77fcaa582da91cb8627dcb6145d 100644 (file)
@@ -161,8 +161,14 @@ static int hfs_readdir(struct file *file, struct dir_context *ctx)
                }
                file->private_data = rd;
                rd->file = file;
+               spin_lock(&HFS_I(inode)->open_dir_lock);
                list_add(&rd->list, &HFS_I(inode)->open_dir_list);
+               spin_unlock(&HFS_I(inode)->open_dir_lock);
        }
+       /*
+        * Can be done after the list insertion; exclusion with
+        * hfs_delete_cat() is provided by directory lock.
+        */
        memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key));
 out:
        hfs_find_exit(&fd);
@@ -173,9 +179,9 @@ static int hfs_dir_release(struct inode *inode, struct file *file)
 {
        struct hfs_readdir_data *rd = file->private_data;
        if (rd) {
-               inode_lock(inode);
+               spin_lock(&HFS_I(inode)->open_dir_lock);
                list_del(&rd->list);
-               inode_unlock(inode);
+               spin_unlock(&HFS_I(inode)->open_dir_lock);
                kfree(rd);
        }
        return 0;
@@ -303,7 +309,7 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 const struct file_operations hfs_dir_operations = {
        .read           = generic_read_dir,
-       .iterate        = hfs_readdir,
+       .iterate_shared = hfs_readdir,
        .llseek         = generic_file_llseek,
        .release        = hfs_dir_release,
 };
index 79daa097929a58510b2c4e8a3745cbe267777e8c..fa3eed86837cfc7308b6e22745eec65d41de981e 100644 (file)
@@ -69,6 +69,7 @@ struct hfs_inode_info {
        struct hfs_cat_key cat_key;
 
        struct list_head open_dir_list;
+       spinlock_t open_dir_lock;
        struct inode *rsrc_inode;
 
        struct mutex extents_lock;
index cb1e5faa2fb71d44fe300a65421e5bfbf1199e04..ba533c79a8065cd886a50e13546323af5546541b 100644 (file)
@@ -187,6 +187,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, umode_t mode)
 
        mutex_init(&HFS_I(inode)->extents_lock);
        INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
+       spin_lock_init(&HFS_I(inode)->open_dir_lock);
        hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
        inode->i_ino = HFS_SB(sb)->next_id++;
        inode->i_mode = mode;
@@ -318,6 +319,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
        HFS_I(inode)->rsrc_inode = NULL;
        mutex_init(&HFS_I(inode)->extents_lock);
        INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
+       spin_lock_init(&HFS_I(inode)->open_dir_lock);
 
        /* Initialize the inode */
        inode->i_uid = hsb->s_uid;