瀏覽代碼

ovl: multi-layer readdir

If multiple lower layers exist, merge them as well in readdir according to
the same rules as merging upper with lower.  I.e. take whiteouts and opaque
directories into account on all but the lowers layer.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Miklos Szeredi 10 年之前
父節點
當前提交
9d7459d834
共有 2 個文件被更改,包括 24 次插入22 次删除
  1. 21 22
      fs/overlayfs/readdir.c
  2. 3 0
      fs/overlayfs/super.c

+ 21 - 22
fs/overlayfs/readdir.c

@@ -261,35 +261,34 @@ static void ovl_dir_reset(struct file *file)
 static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
 static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
 {
 {
 	int err;
 	int err;
-	struct path lowerpath;
-	struct path upperpath;
+	struct path realpath;
 	struct ovl_readdir_data rdd = {
 	struct ovl_readdir_data rdd = {
 		.ctx.actor = ovl_fill_merge,
 		.ctx.actor = ovl_fill_merge,
 		.list = list,
 		.list = list,
 		.root = RB_ROOT,
 		.root = RB_ROOT,
 		.is_merge = false,
 		.is_merge = false,
 	};
 	};
-
-	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) {
-		/*
-		 * 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);
-		list_del(&rdd.middle);
+	int idx, next;
+
+	for (idx = 0; idx != -1; idx = next) {
+		next = ovl_path_next(idx, dentry, &realpath);
+
+		if (next != -1) {
+			rdd.dir = realpath.dentry;
+			err = ovl_dir_read(&realpath, &rdd);
+			if (err)
+				break;
+		} else {
+			/*
+			 * Insert lowest layer entries before upper ones, this
+			 * allows offsets to be reasonably constant
+			 */
+			list_add(&rdd.middle, rdd.list);
+			rdd.is_merge = true;
+			err = ovl_dir_read(&realpath, &rdd);
+			list_del(&rdd.middle);
+		}
 	}
 	}
-out:
 	return err;
 	return err;
 }
 }
 
 

+ 3 - 0
fs/overlayfs/super.c

@@ -81,6 +81,9 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry)
 		} else if (!oe->opaque) {
 		} else if (!oe->opaque) {
 			type |= __OVL_PATH_PURE;
 			type |= __OVL_PATH_PURE;
 		}
 		}
+	} else {
+		if (oe->numlower > 1)
+			type |= __OVL_PATH_MERGE;
 	}
 	}
 	return type;
 	return type;
 }
 }