Skip to contentSkip to conversation

ovl: discard independent cursor in readdir()

RFC PATCH In review hujianyang 1 participant 3 messages Dec 10, 2014 – Dec 11, 2014 Overlay filesystem

lore
Share & tools
lore

hujianyang

author
#0 lore raw

RFC PATCH 1/1 ovl: discard independent cursor in readdir()

Since the ovl_dir_cache is stable during a directory reading, the cursor of struct ovl_dir_file don't need to be an independent entry in the list of a merged directory.

This patch changes *cursor* to a pointer which points to the entry in the ovl_dir_cache. After this, we don't need to check *is_cursor* either.

---
 fs/overlayfs/readdir.c |   33 ++++++++++++---------------------
 1 files changed, 12 insertions(+), 21 deletions(-)
fs/overlayfs/readdir.c +12 -21
index 8087b63..0e46aab 100644
@@ -24,7 +24,6 @@ struct ovl_cache_entry {
 	struct list_head l_node;
 	struct rb_node node;
 	bool is_whiteout;
-	bool is_cursor;
 	char name[];
 };
 
@@ -49,7 +48,7 @@ struct ovl_dir_file {
 	bool is_real;
 	bool is_upper;
 	struct ovl_dir_cache *cache;
-	struct ovl_cache_entry cursor;
+	struct ovl_cache_entry *cursor;
 	struct file *realfile;
 	struct file *upperfile;
 };
@@ -94,7 +93,6 @@ static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len,
 		p->type = d_type;
 		p->ino = ino;
 		p->is_whiteout = false;
-		p->is_cursor = false;
 	}
 
 	return p;
@@ -195,7 +193,7 @@ static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry)
 {
 	struct ovl_dir_cache *cache = od->cache;
 
-	list_del_init(&od->cursor.l_node);
+	od->cursor = NULL;
 	WARN_ON(cache->refcount <= 0);
 	cache->refcount--;
 	if (!cache->refcount) {
@@ -298,13 +296,12 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos)
 	loff_t off = 0;
 
 	list_for_each_entry(p, &od->cache->entries, l_node) {
-		if (p->is_cursor)
-			continue;
 		if (off >= pos)
 			break;
 		off++;
 	}
-	list_move_tail(&od->cursor.l_node, &p->l_node);
+	/* Curosr is safe since the cache is stable */
+	od->cursor = p;
 }
 
 static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
@@ -361,19 +358,14 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
 		ovl_seek_cursor(od, ctx->pos);
 	}
 
-	while (od->cursor.l_node.next != &od->cache->entries) {
-		struct ovl_cache_entry *p;
+	while (!list_is_last(&od->cursor->l_node, &od->cache->entries)) {
+		struct ovl_cache_entry *p = od->cursor;
 
-		p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node);
-		/* Skip cursors */
-		if (!p->is_cursor) {
-			if (!p->is_whiteout) {
-				if (!dir_emit(ctx, p->name, p->len, p->ino, p->type))
-					break;
-			}
-			ctx->pos++;
-		}
-		list_move(&od->cursor.l_node, &p->l_node);
+		if (!p->is_whiteout)
+			if (!dir_emit(ctx, p->name, p->len, p->ino, p->type))
+				break;
+		od->cursor = list_next_entry(p, l_node);
+		ctx->pos++;
 	}
 	return 0;
 }
@@ -492,11 +484,10 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
 		kfree(od);
 		return PTR_ERR(realfile);
 	}
-	INIT_LIST_HEAD(&od->cursor.l_node);
 	od->realfile = realfile;
 	od->is_real = !OVL_TYPE_MERGE(type);
 	od->is_upper = OVL_TYPE_UPPER(type);
-	od->cursor.is_cursor = true;
+	od->cursor = NULL;
 	file->private_data = od;
 
 	return 0;
Signature · 1 line
1.6.0.2
author
#1 lore raw
Quoted 7 lines · hujianyang

Since the ovl_dir_cache is stable during a directory reading, the cursor of struct ovl_dir_file don't need to be an independent entry in the list of a merged directory.

This patch changes *cursor* to a pointer which points to the entry in the ovl_dir_cache. After this, we don't need to check *is_cursor* either.

Sorry, there is something wrong with this patch. Please, drop it~!

author
#2 lore raw
In reply to hujianyang

fs/overlayfs/readdir.c static int ovl_iterate(struct file *file, struct dir_context *ctx) · line 361

Quoted 9 lines · hujianyang

static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)

fs/overlayfs/readdir.c +1 -2
@@ -361,19 +358,14 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
 		ovl_seek_cursor(od, ctx->pos);
 	}
 
-	while (od->cursor.l_node.next != &od->cache->entries) {
-		struct ovl_cache_entry *p;
+	while (!list_is_last(&od->cursor->l_node, &od->cache->entries)) {

Seems I was mistake here. The entry which cursor points to could be the last node in the list. We have finished reading one directory until the cursor points to the head of the entries list.

Here the condition should be:

"""&od->cursor->l_node != &od->cache->entries"""

Sorry for that, I should be more careful.

I will resend this patch with this fix.

Quoted 20 lines
fs/overlayfs/readdir.c +6 -10
+		struct ovl_cache_entry *p = od->cursor;
 
-		p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node);
-		/* Skip cursors */
-		if (!p->is_cursor) {
-			if (!p->is_whiteout) {
-				if (!dir_emit(ctx, p->name, p->len, p->ino, p->type))
-					break;
-			}
-			ctx->pos++;
-		}
-		list_move(&od->cursor.l_node, &p->l_node);
+		if (!p->is_whiteout)
+			if (!dir_emit(ctx, p->name, p->len, p->ino, p->type))
+				break;
+		od->cursor = list_next_entry(p, l_node);
+		ctx->pos++;
 	}
 	return 0;
 }