at master 132 lines 3.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2017-2018 HUAWEI, Inc. 4 * https://www.huawei.com/ 5 * Copyright (C) 2022, Alibaba Cloud 6 */ 7#include "internal.h" 8#include <linux/filelock.h> 9 10static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx, 11 void *dentry_blk, struct erofs_dirent *de, 12 unsigned int nameoff0, unsigned int maxsize) 13{ 14 const struct erofs_dirent *end = dentry_blk + nameoff0; 15 16 while (de < end) { 17 unsigned char d_type = fs_ftype_to_dtype(de->file_type); 18 unsigned int nameoff = le16_to_cpu(de->nameoff); 19 const char *de_name = (char *)dentry_blk + nameoff; 20 unsigned int de_namelen; 21 22 /* the last dirent in the block? */ 23 if (de + 1 >= end) 24 de_namelen = strnlen(de_name, maxsize - nameoff); 25 else 26 de_namelen = le16_to_cpu(de[1].nameoff) - nameoff; 27 28 /* a corrupted entry is found */ 29 if (nameoff + de_namelen > maxsize || 30 de_namelen > EROFS_NAME_LEN) { 31 erofs_err(dir->i_sb, "bogus dirent @ nid %llu", 32 EROFS_I(dir)->nid); 33 DBG_BUGON(1); 34 return -EFSCORRUPTED; 35 } 36 37 if (!dir_emit(ctx, de_name, de_namelen, 38 erofs_nid_to_ino64(EROFS_SB(dir->i_sb), 39 le64_to_cpu(de->nid)), d_type)) 40 return 1; 41 ++de; 42 ctx->pos += sizeof(struct erofs_dirent); 43 } 44 return 0; 45} 46 47static int erofs_readdir(struct file *f, struct dir_context *ctx) 48{ 49 struct inode *dir = file_inode(f); 50 struct erofs_buf buf = __EROFS_BUF_INITIALIZER; 51 struct super_block *sb = dir->i_sb; 52 struct file_ra_state *ra = &f->f_ra; 53 unsigned long bsz = sb->s_blocksize; 54 unsigned int ofs = erofs_blkoff(sb, ctx->pos); 55 pgoff_t ra_pages = DIV_ROUND_UP_POW2( 56 EROFS_I_SB(dir)->dir_ra_bytes, PAGE_SIZE); 57 pgoff_t nr_pages = DIV_ROUND_UP_POW2(dir->i_size, PAGE_SIZE); 58 int err = 0; 59 bool initial = true; 60 61 buf.mapping = dir->i_mapping; 62 while (ctx->pos < dir->i_size) { 63 erofs_off_t dbstart = ctx->pos - ofs; 64 struct erofs_dirent *de; 65 unsigned int nameoff, maxsize; 66 67 if (fatal_signal_pending(current)) { 68 err = -ERESTARTSYS; 69 break; 70 } 71 72 /* readahead blocks to enhance performance for large directories */ 73 if (ra_pages) { 74 pgoff_t idx = DIV_ROUND_UP_POW2(ctx->pos, PAGE_SIZE); 75 pgoff_t pages = min(nr_pages - idx, ra_pages); 76 77 if (pages > 1 && !ra_has_index(ra, idx)) 78 page_cache_sync_readahead(dir->i_mapping, ra, 79 f, idx, pages); 80 } 81 82 de = erofs_bread(&buf, dbstart, true); 83 if (IS_ERR(de)) { 84 erofs_err(sb, "failed to readdir of logical block %llu of nid %llu", 85 erofs_blknr(sb, dbstart), EROFS_I(dir)->nid); 86 err = PTR_ERR(de); 87 break; 88 } 89 90 nameoff = le16_to_cpu(de->nameoff); 91 if (nameoff < sizeof(struct erofs_dirent) || nameoff >= bsz) { 92 erofs_err(sb, "invalid de[0].nameoff %u @ nid %llu", 93 nameoff, EROFS_I(dir)->nid); 94 err = -EFSCORRUPTED; 95 break; 96 } 97 98 maxsize = min_t(unsigned int, dir->i_size - dbstart, bsz); 99 /* search dirents at the arbitrary position */ 100 if (initial) { 101 initial = false; 102 ofs = roundup(ofs, sizeof(struct erofs_dirent)); 103 ctx->pos = dbstart + ofs; 104 } 105 106 err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs, 107 nameoff, maxsize); 108 if (err) 109 break; 110 ctx->pos = dbstart + maxsize; 111 ofs = 0; 112 cond_resched(); 113 } 114 erofs_put_metabuf(&buf); 115 if (EROFS_I(dir)->dot_omitted && ctx->pos == dir->i_size) { 116 if (!dir_emit_dot(f, ctx)) 117 return 0; 118 ++ctx->pos; 119 } 120 return err < 0 ? err : 0; 121} 122 123const struct file_operations erofs_dir_fops = { 124 .llseek = generic_file_llseek, 125 .read = generic_read_dir, 126 .iterate_shared = erofs_readdir, 127 .unlocked_ioctl = erofs_ioctl, 128#ifdef CONFIG_COMPAT 129 .compat_ioctl = erofs_compat_ioctl, 130#endif 131 .setlease = generic_setlease, 132};