ovl: make path-type a bitmap
[deliverable/linux.git] / fs / overlayfs / readdir.c
index 2a7ef4f8e2a6c37e033b771413fc66f75b567556..481e44873b65e8e23a246d2ff078ad049e5a1dd9 100644 (file)
@@ -40,6 +40,7 @@ struct ovl_readdir_data {
        struct rb_root root;
        struct list_head *list;
        struct list_head middle;
+       struct dentry *dir;
        int count;
        int err;
 };
@@ -126,6 +127,32 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
        if (p == NULL)
                return -ENOMEM;
 
+       if (d_type == DT_CHR) {
+               struct dentry *dentry;
+               const struct cred *old_cred;
+               struct cred *override_cred;
+
+               override_cred = prepare_creds();
+               if (!override_cred) {
+                       kfree(p);
+                       return -ENOMEM;
+               }
+
+               /*
+                * CAP_DAC_OVERRIDE for lookup
+                */
+               cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
+               old_cred = override_creds(override_cred);
+
+               dentry = lookup_one_len(name, rdd->dir, len);
+               if (!IS_ERR(dentry)) {
+                       p->is_whiteout = ovl_is_whiteout(dentry);
+                       dput(dentry);
+               }
+               revert_creds(old_cred);
+               put_cred(override_cred);
+       }
+
        list_add_tail(&p->l_node, rdd->list);
        rb_link_node(&p->node, parent, newp);
        rb_insert_color(&p->node, &rdd->root);
@@ -226,59 +253,16 @@ static void ovl_dir_reset(struct file *file)
                ovl_cache_put(od, dentry);
                od->cache = NULL;
        }
-       WARN_ON(!od->is_real && type != OVL_PATH_MERGE);
-       if (od->is_real && type == OVL_PATH_MERGE)
+       WARN_ON(!od->is_real && !OVL_TYPE_MERGE(type));
+       if (od->is_real && OVL_TYPE_MERGE(type))
                od->is_real = false;
 }
 
-static int ovl_dir_mark_whiteouts(struct dentry *dir,
-                                 struct ovl_readdir_data *rdd)
-{
-       struct ovl_cache_entry *p;
-       struct dentry *dentry;
-       const struct cred *old_cred;
-       struct cred *override_cred;
-
-       override_cred = prepare_creds();
-       if (!override_cred) {
-               ovl_cache_free(rdd->list);
-               return -ENOMEM;
-       }
-
-       /*
-        * CAP_DAC_OVERRIDE for lookup
-        */
-       cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
-       old_cred = override_creds(override_cred);
-
-       mutex_lock(&dir->d_inode->i_mutex);
-       list_for_each_entry(p, rdd->list, l_node) {
-               if (p->is_cursor)
-                       continue;
-
-               if (p->type != DT_CHR)
-                       continue;
-
-               dentry = lookup_one_len(p->name, dir, p->len);
-               if (IS_ERR(dentry))
-                       continue;
-
-               p->is_whiteout = ovl_is_whiteout(dentry);
-               dput(dentry);
-       }
-       mutex_unlock(&dir->d_inode->i_mutex);
-
-       revert_creds(old_cred);
-       put_cred(override_cred);
-
-       return 0;
-}
-
-static inline int ovl_dir_read_merged(struct path *upperpath,
-                                     struct path *lowerpath,
-                                     struct list_head *list)
+static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
 {
        int err;
+       struct path lowerpath;
+       struct path upperpath;
        struct ovl_readdir_data rdd = {
                .ctx.actor = ovl_fill_merge,
                .list = list,
@@ -286,25 +270,23 @@ static inline int ovl_dir_read_merged(struct path *upperpath,
                .is_merge = false,
        };
 
-       if (upperpath->dentry) {
-               err = ovl_dir_read(upperpath, &rdd);
+       ovl_path_lower(dentry, &lowerpath);
+       ovl_path_upper(dentry, &upperpath);
+
+       if (upperpath.dentry) {
+               rdd.dir = upperpath.dentry;
+               err = ovl_dir_read(&upperpath, &rdd);
                if (err)
                        goto out;
-
-               if (lowerpath->dentry) {
-                       err = ovl_dir_mark_whiteouts(upperpath->dentry, &rdd);
-                       if (err)
-                               goto out;
-               }
        }
-       if (lowerpath->dentry) {
+       if (lowerpath.dentry) {
                /*
                 * Insert lowerpath entries before upperpath ones, this allows
                 * offsets to be reasonably constant
                 */
                list_add(&rdd.middle, rdd.list);
                rdd.is_merge = true;
-               err = ovl_dir_read(lowerpath, &rdd);
+               err = ovl_dir_read(&lowerpath, &rdd);
                list_del(&rdd.middle);
        }
 out:
@@ -329,8 +311,6 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos)
 static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
 {
        int res;
-       struct path lowerpath;
-       struct path upperpath;
        struct ovl_dir_cache *cache;
 
        cache = ovl_dir_cache(dentry);
@@ -347,10 +327,7 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
        cache->refcount = 1;
        INIT_LIST_HEAD(&cache->entries);
 
-       ovl_path_lower(dentry, &lowerpath);
-       ovl_path_upper(dentry, &upperpath);
-
-       res = ovl_dir_read_merged(&upperpath, &lowerpath, &cache->entries);
+       res = ovl_dir_read_merged(dentry, &cache->entries);
        if (res) {
                ovl_cache_free(&cache->entries);
                kfree(cache);
@@ -452,10 +429,10 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
        /*
         * Need to check if we started out being a lower dir, but got copied up
         */
-       if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) {
+       if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
                struct inode *inode = file_inode(file);
 
-               realfile =lockless_dereference(od->upperfile);
+               realfile = lockless_dereference(od->upperfile);
                if (!realfile) {
                        struct path upperpath;
 
@@ -518,8 +495,8 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
        }
        INIT_LIST_HEAD(&od->cursor.l_node);
        od->realfile = realfile;
-       od->is_real = (type != OVL_PATH_MERGE);
-       od->is_upper = (type != OVL_PATH_LOWER);
+       od->is_real = !OVL_TYPE_MERGE(type);
+       od->is_upper = OVL_TYPE_UPPER(type);
        od->cursor.is_cursor = true;
        file->private_data = od;
 
@@ -538,14 +515,9 @@ const struct file_operations ovl_dir_operations = {
 int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
 {
        int err;
-       struct path lowerpath;
-       struct path upperpath;
        struct ovl_cache_entry *p;
 
-       ovl_path_upper(dentry, &upperpath);
-       ovl_path_lower(dentry, &lowerpath);
-
-       err = ovl_dir_read_merged(&upperpath, &lowerpath, list);
+       err = ovl_dir_read_merged(dentry, list);
        if (err)
                return err;
 
This page took 0.025908 seconds and 5 git commands to generate.