272 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2000-2001 Christoph Hellwig.4 * Copyright (c) 2016 Krzysztof Blaszkowski5 */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 dentry44 * @ip: directory inode45 * @dp: dentry for which we want to find a direct46 * @ppp: gets filled with the page the return value sits in47 *48 * Description:49 * vxfs_find_entry finds a &struct vxfs_direct for the VFS directory50 * cache entry @dp. @ppp will be filled with the page the return51 * 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 else113 break;114 }115 116 return de_exit;117}118 119/**120 * vxfs_inode_by_name - find inode number for dentry121 * @dip: directory to search in122 * @dp: dentry we search for123 *124 * Description:125 * vxfs_inode_by_name finds out the inode number of126 * the path component described by @dp in @dip.127 *128 * Returns:129 * The wanted inode number on success, else Zero.130 */131static ino_t132vxfs_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 component150 * @dip: dir in which we lookup151 * @dp: dentry we lookup152 * @flags: lookup flags153 *154 * Description:155 * vxfs_lookup tries to lookup the pathname component described156 * by @dp in @dip.157 *158 * Returns:159 * A NULL-pointer on success, else a negative error code encoded160 * 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 directory179 * @fp: the directory to read180 * @ctx: dir_context for filldir/readdir181 *182 * Description:183 * vxfs_readdir fills @retp with directory entries from @fp184 * using the VFS supplied callback @filler.185 *186 * Returns:187 * Zero.188 */189static int190vxfs_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 269out:270 return 0;271}272