Skip to content

Commit e9dfe33

Browse files
committed
erofs: support dot-omitted directories
There's no need to record "." dirents in the directory data (while they could be used for sanity checks, they aren't very useful.) Omitting "." dirents also improves directory data deduplication. Use a per-inode (instead of per-sb) flag to indicate if the "." dirent is omitted or not, ensuring compatibility with incremental builds. It also reuses EROFS_I_NLINK_1_BIT, as it has very limited use cases for directories with `nlink = 1`. Emit the "." entry as the last virtual dirent in the directory because it is _much_ less frequently used than the ".." dirent. It also keeps `f_pos` meaningful, as it strictly follows the directory data when it's less than i_size. Signed-off-by: Gao Xiang <[email protected]> Acked-by: Chao Yu <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2e1473d commit e9dfe33

File tree

4 files changed

+10
-1
lines changed

4 files changed

+10
-1
lines changed

fs/erofs/dir.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
9090
ofs = 0;
9191
}
9292
erofs_put_metabuf(&buf);
93+
if (EROFS_I(dir)->dot_omitted && ctx->pos == dir->i_size) {
94+
if (!dir_emit_dot(f, ctx))
95+
return 0;
96+
++ctx->pos;
97+
}
9398
return err < 0 ? err : 0;
9499
}
95100

fs/erofs/erofs_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ static inline bool erofs_inode_is_data_compressed(unsigned int datamode)
116116
#define EROFS_I_VERSION_BIT 0
117117
#define EROFS_I_DATALAYOUT_BIT 1
118118
#define EROFS_I_NLINK_1_BIT 4 /* non-directory compact inodes only */
119+
#define EROFS_I_DOT_OMITTED_BIT 4 /* (directories) omit the `.` dirent */
119120
#define EROFS_I_ALL ((1 << (EROFS_I_NLINK_1_BIT + 1)) - 1)
120121

121122
/* indicate chunk blkbits, thus 'chunksize = blocksize << chunk blkbits' */

fs/erofs/inode.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,10 @@ static int erofs_read_inode(struct inode *inode)
136136
goto err_out;
137137
}
138138
switch (inode->i_mode & S_IFMT) {
139-
case S_IFREG:
140139
case S_IFDIR:
140+
vi->dot_omitted = (ifmt >> EROFS_I_DOT_OMITTED_BIT) & 1;
141+
fallthrough;
142+
case S_IFREG:
141143
case S_IFLNK:
142144
vi->startblk = le32_to_cpu(copied.i_u.startblk_lo) |
143145
((u64)le16_to_cpu(copied.i_nb.startblk_hi) << 32);

fs/erofs/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ struct erofs_inode {
245245

246246
unsigned char datalayout;
247247
unsigned char inode_isize;
248+
bool dot_omitted;
248249
unsigned int xattr_isize;
249250

250251
unsigned int xattr_name_filter;

0 commit comments

Comments
 (0)