vxfs_lookup.c (6013B)
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 28static struct dentry * vxfs_lookup(struct inode *, struct dentry *, unsigned int); 29static int vxfs_readdir(struct file *, struct dir_context *); 30 31const struct inode_operations vxfs_dir_inode_ops = { 32 .lookup = vxfs_lookup, 33}; 34 35const 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 */ 56static struct vxfs_direct * 57vxfs_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 */ 131static ino_t 132vxfs_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 */ 162static struct dentry * 163vxfs_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 * @retp: return buffer 181 * @filler: filldir callback 182 * 183 * Description: 184 * vxfs_readdir fills @retp with directory entries from @fp 185 * using the VFS supplied callback @filler. 186 * 187 * Returns: 188 * Zero. 189 */ 190static int 191vxfs_readdir(struct file *fp, struct dir_context *ctx) 192{ 193 struct inode *ip = file_inode(fp); 194 struct super_block *sbp = ip->i_sb; 195 u_long bsize = sbp->s_blocksize; 196 loff_t pos, limit; 197 struct vxfs_sb_info *sbi = VXFS_SBI(sbp); 198 199 if (ctx->pos == 0) { 200 if (!dir_emit_dot(fp, ctx)) 201 goto out; 202 ctx->pos++; 203 } 204 if (ctx->pos == 1) { 205 if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR)) 206 goto out; 207 ctx->pos++; 208 } 209 210 limit = VXFS_DIRROUND(ip->i_size); 211 if (ctx->pos > limit) 212 goto out; 213 214 pos = ctx->pos & ~3L; 215 216 while (pos < limit) { 217 struct page *pp; 218 char *kaddr; 219 int pg_ofs = pos & ~PAGE_MASK; 220 int rc = 0; 221 222 pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT); 223 if (IS_ERR(pp)) 224 return -ENOMEM; 225 226 kaddr = (char *)page_address(pp); 227 228 while (pg_ofs < PAGE_SIZE && pos < limit) { 229 struct vxfs_direct *de; 230 231 if ((pos & (bsize - 1)) < 4) { 232 struct vxfs_dirblk *dbp = 233 (struct vxfs_dirblk *) 234 (kaddr + (pos & ~PAGE_MASK)); 235 int overhead = VXFS_DIRBLKOV(sbi, dbp); 236 237 pos += overhead; 238 pg_ofs += overhead; 239 } 240 de = (struct vxfs_direct *)(kaddr + pg_ofs); 241 242 if (!de->d_reclen) { 243 pos += bsize - 1; 244 pos &= ~(bsize - 1); 245 break; 246 } 247 248 pg_ofs += fs16_to_cpu(sbi, de->d_reclen); 249 pos += fs16_to_cpu(sbi, de->d_reclen); 250 if (!de->d_ino) 251 continue; 252 253 rc = dir_emit(ctx, de->d_name, 254 fs16_to_cpu(sbi, de->d_namelen), 255 fs32_to_cpu(sbi, de->d_ino), 256 DT_UNKNOWN); 257 if (!rc) { 258 /* the dir entry was not read, fix pos. */ 259 pos -= fs16_to_cpu(sbi, de->d_reclen); 260 break; 261 } 262 } 263 vxfs_put_page(pp); 264 if (!rc) 265 break; 266 } 267 268 ctx->pos = pos | 2; 269 270out: 271 return 0; 272}