brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · 1b0bca8 Raw
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