]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/libfs.c
fs: dcache scale subdirs
[karo-tx-linux.git] / fs / libfs.c
index 433e7139c23aa179905fb3e35636f3c2600098d4..cc4794914b52273edeaa0f29f0ca559d8f279559 100644 (file)
@@ -81,7 +81,8 @@ int dcache_dir_close(struct inode *inode, struct file *file)
 
 loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
 {
-       mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
+       struct dentry *dentry = file->f_path.dentry;
+       mutex_lock(&dentry->d_inode->i_mutex);
        switch (origin) {
                case 1:
                        offset += file->f_pos;
@@ -89,7 +90,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
                        if (offset >= 0)
                                break;
                default:
-                       mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
+                       mutex_unlock(&dentry->d_inode->i_mutex);
                        return -EINVAL;
        }
        if (offset != file->f_pos) {
@@ -100,22 +101,25 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
                        loff_t n = file->f_pos - 2;
 
                        spin_lock(&dcache_lock);
+                       spin_lock(&dentry->d_lock);
+                       /* d_lock not required for cursor */
                        list_del(&cursor->d_u.d_child);
-                       p = file->f_path.dentry->d_subdirs.next;
-                       while (n && p != &file->f_path.dentry->d_subdirs) {
+                       p = dentry->d_subdirs.next;
+                       while (n && p != &dentry->d_subdirs) {
                                struct dentry *next;
                                next = list_entry(p, struct dentry, d_u.d_child);
-                               spin_lock(&next->d_lock);
+                               spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
                                if (simple_positive(next))
                                        n--;
                                spin_unlock(&next->d_lock);
                                p = p->next;
                        }
                        list_add_tail(&cursor->d_u.d_child, p);
+                       spin_unlock(&dentry->d_lock);
                        spin_unlock(&dcache_lock);
                }
        }
-       mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
+       mutex_unlock(&dentry->d_inode->i_mutex);
        return offset;
 }
 
@@ -156,6 +160,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
                        /* fallthrough */
                default:
                        spin_lock(&dcache_lock);
+                       spin_lock(&dentry->d_lock);
                        if (filp->f_pos == 2)
                                list_move(q, &dentry->d_subdirs);
 
@@ -169,6 +174,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
                                }
 
                                spin_unlock(&next->d_lock);
+                               spin_unlock(&dentry->d_lock);
                                spin_unlock(&dcache_lock);
                                if (filldir(dirent, next->d_name.name, 
                                            next->d_name.len, filp->f_pos, 
@@ -176,11 +182,15 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
                                            dt_type(next->d_inode)) < 0)
                                        return 0;
                                spin_lock(&dcache_lock);
+                               spin_lock(&dentry->d_lock);
+                               spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
                                /* next is still alive */
                                list_move(q, p);
+                               spin_unlock(&next->d_lock);
                                p = q;
                                filp->f_pos++;
                        }
+                       spin_unlock(&dentry->d_lock);
                        spin_unlock(&dcache_lock);
        }
        return 0;
@@ -276,6 +286,7 @@ int simple_empty(struct dentry *dentry)
        int ret = 0;
 
        spin_lock(&dcache_lock);
+       spin_lock(&dentry->d_lock);
        list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
                spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
                if (simple_positive(child)) {
@@ -286,6 +297,7 @@ int simple_empty(struct dentry *dentry)
        }
        ret = 1;
 out:
+       spin_unlock(&dentry->d_lock);
        spin_unlock(&dcache_lock);
        return ret;
 }