1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2000-2001 Christoph Hellwig. 4 * Copyright (c) 2016 Krzysztof Blaszkowski 5 */ 6 7 /* 8 * Veritas filesystem driver - lookup and other directory related code. 9 */ 10 #include <linux/fs.h> 11 #include <linux/time.h> 12 #include <linux/mm.h> 13 #include <linux/highmem.h> 14 #include <linux/kernel.h> 15 #include <linux/pagemap.h> 16 17 #include "vxfs.h" 18 #include "vxfs_dir.h" 19 #include "vxfs_inode.h" 20 #include "vxfs_extern.h" 21 22 /* 23 * Number of VxFS blocks per page. 24 */ 25 #define VXFS_BLOCK_PER_PAGE(sbp) ((PAGE_SIZE / (sbp)->s_blocksize)) 26 27 28 static struct dentry * vxfs_lookup(struct inode *, struct dentry *, unsigned int); 29 static int vxfs_readdir(struct file *, struct dir_context *); 30 31 const struct inode_operations vxfs_dir_inode_ops = { 32 .lookup = vxfs_lookup, 33 }; 34 35 const struct file_operations vxfs_dir_operations = { 36 .llseek = generic_file_llseek, 37 .read = generic_read_dir, 38 .iterate_shared = vxfs_readdir, 39 }; 40 41 42 /** 43 * vxfs_find_entry - find a mathing directory entry for a dentry 44 * @ip: directory inode 45 * @dp: dentry for which we want to find a direct 46 * @ppp: gets filled with the page the return value sits in 47 * 48 * Description: 49 * vxfs_find_entry finds a &struct vxfs_direct for the VFS directory 50 * cache entry @dp. @ppp will be filled with the page the return 51 * value resides in. 52 * 53 * Returns: 54 * The wanted direct on success, else a NULL pointer. 55 */ 56 static struct vxfs_direct * 57 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp) 58 { 59 u_long bsize = ip->i_sb->s_blocksize; 60 const char *name = dp->d_name.name; 61 int namelen = dp->d_name.len; 62 loff_t limit = VXFS_DIRROUND(ip->i_size); 63 struct vxfs_direct *de_exit = NULL; 64 loff_t pos = 0; 65 struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb); 66 67 while (pos < limit) { 68 struct page *pp; 69 char *kaddr; 70 int pg_ofs = pos & ~PAGE_MASK; 71 72 pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT); 73 if (IS_ERR(pp)) 74 return NULL; 75 kaddr = (char *)page_address(pp); 76 77 while (pg_ofs < PAGE_SIZE && pos < limit) { 78 struct vxfs_direct *de; 79 80 if ((pos & (bsize - 1)) < 4) { 81 struct vxfs_dirblk *dbp = 82 (struct vxfs_dirblk *) 83 (kaddr + (pos & ~PAGE_MASK)); 84 int overhead = VXFS_DIRBLKOV(sbi, dbp); 85 86 pos += overhead; 87 pg_ofs += overhead; 88 } 89 de = (struct vxfs_direct *)(kaddr + pg_ofs); 90 91 if (!de->d_reclen) { 92 pos += bsize - 1; 93 pos &= ~(bsize - 1); 94 break; 95 } 96 97 pg_ofs += fs16_to_cpu(sbi, de->d_reclen); 98 pos += fs16_to_cpu(sbi, de->d_reclen); 99 if (!de->d_ino) 100 continue; 101 102 if (namelen != fs16_to_cpu(sbi, de->d_namelen)) 103 continue; 104 if (!memcmp(name, de->d_name, namelen)) { 105 *ppp = pp; 106 de_exit = de; 107 break; 108 } 109 } 110 if (!de_exit) 111 vxfs_put_page(pp); 112 else 113 break; 114 } 115 116 return de_exit; 117 } 118 119 /** 120 * vxfs_inode_by_name - find inode number for dentry 121 * @dip: directory to search in 122 * @dp: dentry we search for 123 * 124 * Description: 125 * vxfs_inode_by_name finds out the inode number of 126 * the path component described by @dp in @dip. 127 * 128 * Returns: 129 * The wanted inode number on success, else Zero. 130 */ 131 static ino_t 132 vxfs_inode_by_name(struct inode *dip, struct dentry *dp) 133 { 134 struct vxfs_direct *de; 135 struct page *pp; 136 ino_t ino = 0; 137 138 de = vxfs_find_entry(dip, dp, &pp); 139 if (de) { 140 ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino); 141 kunmap(pp); 142 put_page(pp); 143 } 144 145 return (ino); 146 } 147 148 /** 149 * vxfs_lookup - lookup pathname component 150 * @dip: dir in which we lookup 151 * @dp: dentry we lookup 152 * @flags: lookup flags 153 * 154 * Description: 155 * vxfs_lookup tries to lookup the pathname component described 156 * by @dp in @dip. 157 * 158 * Returns: 159 * A NULL-pointer on success, else a negative error code encoded 160 * in the return pointer. 161 */ 162 static struct dentry * 163 vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags) 164 { 165 struct inode *ip = NULL; 166 ino_t ino; 167 168 if (dp->d_name.len > VXFS_NAMELEN) 169 return ERR_PTR(-ENAMETOOLONG); 170 171 ino = vxfs_inode_by_name(dip, dp); 172 if (ino) 173 ip = vxfs_iget(dip->i_sb, ino); 174 return d_splice_alias(ip, dp); 175 } 176 177 /** 178 * vxfs_readdir - read a directory 179 * @fp: the directory to read 180 * @ctx: dir_context for filldir/readdir 181 * 182 * Description: 183 * vxfs_readdir fills @retp with directory entries from @fp 184 * using the VFS supplied callback @filler. 185 * 186 * Returns: 187 * Zero. 188 */ 189 static int 190 vxfs_readdir(struct file *fp, struct dir_context *ctx) 191 { 192 struct inode *ip = file_inode(fp); 193 struct super_block *sbp = ip->i_sb; 194 u_long bsize = sbp->s_blocksize; 195 loff_t pos, limit; 196 struct vxfs_sb_info *sbi = VXFS_SBI(sbp); 197 198 if (ctx->pos == 0) { 199 if (!dir_emit_dot(fp, ctx)) 200 goto out; 201 ctx->pos++; 202 } 203 if (ctx->pos == 1) { 204 if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR)) 205 goto out; 206 ctx->pos++; 207 } 208 209 limit = VXFS_DIRROUND(ip->i_size); 210 if (ctx->pos > limit) 211 goto out; 212 213 pos = ctx->pos & ~3L; 214 215 while (pos < limit) { 216 struct page *pp; 217 char *kaddr; 218 int pg_ofs = pos & ~PAGE_MASK; 219 int rc = 0; 220 221 pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT); 222 if (IS_ERR(pp)) 223 return -ENOMEM; 224 225 kaddr = (char *)page_address(pp); 226 227 while (pg_ofs < PAGE_SIZE && pos < limit) { 228 struct vxfs_direct *de; 229 230 if ((pos & (bsize - 1)) < 4) { 231 struct vxfs_dirblk *dbp = 232 (struct vxfs_dirblk *) 233 (kaddr + (pos & ~PAGE_MASK)); 234 int overhead = VXFS_DIRBLKOV(sbi, dbp); 235 236 pos += overhead; 237 pg_ofs += overhead; 238 } 239 de = (struct vxfs_direct *)(kaddr + pg_ofs); 240 241 if (!de->d_reclen) { 242 pos += bsize - 1; 243 pos &= ~(bsize - 1); 244 break; 245 } 246 247 pg_ofs += fs16_to_cpu(sbi, de->d_reclen); 248 pos += fs16_to_cpu(sbi, de->d_reclen); 249 if (!de->d_ino) 250 continue; 251 252 rc = dir_emit(ctx, de->d_name, 253 fs16_to_cpu(sbi, de->d_namelen), 254 fs32_to_cpu(sbi, de->d_ino), 255 DT_UNKNOWN); 256 if (!rc) { 257 /* the dir entry was not read, fix pos. */ 258 pos -= fs16_to_cpu(sbi, de->d_reclen); 259 break; 260 } 261 } 262 vxfs_put_page(pp); 263 if (!rc) 264 break; 265 } 266 267 ctx->pos = pos | 2; 268 269 out: 270 return 0; 271 } 272
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.