• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/fs/freevxfs/
1/*
2 * Copyright (c) 2000-2001 Christoph Hellwig.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions, and the following disclaimer,
10 *    without modification.
11 * 2. The name of the author may not be used to endorse or promote products
12 *    derived from this software without specific prior written permission.
13 *
14 * Alternatively, this software may be distributed under the terms of the
15 * GNU General Public License ("GPL").
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * Veritas filesystem driver - lookup and other directory related code.
32 */
33#include <linux/fs.h>
34#include <linux/time.h>
35#include <linux/mm.h>
36#include <linux/highmem.h>
37#include <linux/kernel.h>
38#include <linux/pagemap.h>
39#include <linux/smp_lock.h>
40
41#include "vxfs.h"
42#include "vxfs_dir.h"
43#include "vxfs_inode.h"
44#include "vxfs_extern.h"
45
46/*
47 * Number of VxFS blocks per page.
48 */
49#define VXFS_BLOCK_PER_PAGE(sbp)  ((PAGE_CACHE_SIZE / (sbp)->s_blocksize))
50
51
52static struct dentry *	vxfs_lookup(struct inode *, struct dentry *, struct nameidata *);
53static int		vxfs_readdir(struct file *, void *, filldir_t);
54
55const struct inode_operations vxfs_dir_inode_ops = {
56	.lookup =		vxfs_lookup,
57};
58
59const struct file_operations vxfs_dir_operations = {
60	.llseek =		generic_file_llseek,
61	.read =			generic_read_dir,
62	.readdir =		vxfs_readdir,
63};
64
65
66static inline u_long
67dir_pages(struct inode *inode)
68{
69	return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
70}
71
72static inline u_long
73dir_blocks(struct inode *ip)
74{
75	u_long			bsize = ip->i_sb->s_blocksize;
76	return (ip->i_size + bsize - 1) & ~(bsize - 1);
77}
78
79/*
80 * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
81 *
82 * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
83 */
84static inline int
85vxfs_match(int len, const char * const name, struct vxfs_direct *de)
86{
87	if (len != de->d_namelen)
88		return 0;
89	if (!de->d_ino)
90		return 0;
91	return !memcmp(name, de->d_name, len);
92}
93
94static inline struct vxfs_direct *
95vxfs_next_entry(struct vxfs_direct *de)
96{
97	return ((struct vxfs_direct *)((char*)de + de->d_reclen));
98}
99
100/**
101 * vxfs_find_entry - find a mathing directory entry for a dentry
102 * @ip:		directory inode
103 * @dp:		dentry for which we want to find a direct
104 * @ppp:	gets filled with the page the return value sits in
105 *
106 * Description:
107 *   vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
108 *   cache entry @dp.  @ppp will be filled with the page the return
109 *   value resides in.
110 *
111 * Returns:
112 *   The wanted direct on success, else a NULL pointer.
113 */
114static struct vxfs_direct *
115vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
116{
117	u_long				npages, page, nblocks, pblocks, block;
118	u_long				bsize = ip->i_sb->s_blocksize;
119	const char			*name = dp->d_name.name;
120	int				namelen = dp->d_name.len;
121
122	npages = dir_pages(ip);
123	nblocks = dir_blocks(ip);
124	pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
125
126	for (page = 0; page < npages; page++) {
127		caddr_t			kaddr;
128		struct page		*pp;
129
130		pp = vxfs_get_page(ip->i_mapping, page);
131		if (IS_ERR(pp))
132			continue;
133		kaddr = (caddr_t)page_address(pp);
134
135		for (block = 0; block <= nblocks && block <= pblocks; block++) {
136			caddr_t			baddr, limit;
137			struct vxfs_dirblk	*dbp;
138			struct vxfs_direct	*de;
139
140			baddr = kaddr + (block * bsize);
141			limit = baddr + bsize - VXFS_DIRLEN(1);
142
143			dbp = (struct vxfs_dirblk *)baddr;
144			de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
145
146			for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
147				if (!de->d_reclen)
148					break;
149				if (!de->d_ino)
150					continue;
151				if (vxfs_match(namelen, name, de)) {
152					*ppp = pp;
153					return (de);
154				}
155			}
156		}
157		vxfs_put_page(pp);
158	}
159
160	return NULL;
161}
162
163/**
164 * vxfs_inode_by_name - find inode number for dentry
165 * @dip:	directory to search in
166 * @dp:		dentry we seach for
167 *
168 * Description:
169 *   vxfs_inode_by_name finds out the inode number of
170 *   the path component described by @dp in @dip.
171 *
172 * Returns:
173 *   The wanted inode number on success, else Zero.
174 */
175static ino_t
176vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
177{
178	struct vxfs_direct		*de;
179	struct page			*pp;
180	ino_t				ino = 0;
181
182	de = vxfs_find_entry(dip, dp, &pp);
183	if (de) {
184		ino = de->d_ino;
185		kunmap(pp);
186		page_cache_release(pp);
187	}
188
189	return (ino);
190}
191
192/**
193 * vxfs_lookup - lookup pathname component
194 * @dip:	dir in which we lookup
195 * @dp:		dentry we lookup
196 * @nd:		lookup nameidata
197 *
198 * Description:
199 *   vxfs_lookup tries to lookup the pathname component described
200 *   by @dp in @dip.
201 *
202 * Returns:
203 *   A NULL-pointer on success, else an negative error code encoded
204 *   in the return pointer.
205 */
206static struct dentry *
207vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
208{
209	struct inode		*ip = NULL;
210	ino_t			ino;
211
212	if (dp->d_name.len > VXFS_NAMELEN)
213		return ERR_PTR(-ENAMETOOLONG);
214
215	lock_kernel();
216	ino = vxfs_inode_by_name(dip, dp);
217	if (ino) {
218		ip = vxfs_iget(dip->i_sb, ino);
219		if (IS_ERR(ip)) {
220			unlock_kernel();
221			return ERR_CAST(ip);
222		}
223	}
224	unlock_kernel();
225	d_add(dp, ip);
226	return NULL;
227}
228
229/**
230 * vxfs_readdir - read a directory
231 * @fp:		the directory to read
232 * @retp:	return buffer
233 * @filler:	filldir callback
234 *
235 * Description:
236 *   vxfs_readdir fills @retp with directory entries from @fp
237 *   using the VFS supplied callback @filler.
238 *
239 * Returns:
240 *   Zero.
241 */
242static int
243vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
244{
245	struct inode		*ip = fp->f_path.dentry->d_inode;
246	struct super_block	*sbp = ip->i_sb;
247	u_long			bsize = sbp->s_blocksize;
248	u_long			page, npages, block, pblocks, nblocks, offset;
249	loff_t			pos;
250
251	lock_kernel();
252
253	switch ((long)fp->f_pos) {
254	case 0:
255		if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
256			goto out;
257		fp->f_pos++;
258		/* fallthrough */
259	case 1:
260		if (filler(retp, "..", 2, fp->f_pos, VXFS_INO(ip)->vii_dotdot, DT_DIR) < 0)
261			goto out;
262		fp->f_pos++;
263		/* fallthrough */
264	}
265
266	pos = fp->f_pos - 2;
267
268	if (pos > VXFS_DIRROUND(ip->i_size)) {
269		unlock_kernel();
270		return 0;
271	}
272
273	npages = dir_pages(ip);
274	nblocks = dir_blocks(ip);
275	pblocks = VXFS_BLOCK_PER_PAGE(sbp);
276
277	page = pos >> PAGE_CACHE_SHIFT;
278	offset = pos & ~PAGE_CACHE_MASK;
279	block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
280
281	for (; page < npages; page++, block = 0) {
282		caddr_t			kaddr;
283		struct page		*pp;
284
285		pp = vxfs_get_page(ip->i_mapping, page);
286		if (IS_ERR(pp))
287			continue;
288		kaddr = (caddr_t)page_address(pp);
289
290		for (; block <= nblocks && block <= pblocks; block++) {
291			caddr_t			baddr, limit;
292			struct vxfs_dirblk	*dbp;
293			struct vxfs_direct	*de;
294
295			baddr = kaddr + (block * bsize);
296			limit = baddr + bsize - VXFS_DIRLEN(1);
297
298			dbp = (struct vxfs_dirblk *)baddr;
299			de = (struct vxfs_direct *)
300				(offset ?
301				 (kaddr + offset) :
302				 (baddr + VXFS_DIRBLKOV(dbp)));
303
304			for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
305				int	over;
306
307				if (!de->d_reclen)
308					break;
309				if (!de->d_ino)
310					continue;
311
312				offset = (caddr_t)de - kaddr;
313				over = filler(retp, de->d_name, de->d_namelen,
314					((page << PAGE_CACHE_SHIFT) | offset) + 2,
315					de->d_ino, DT_UNKNOWN);
316				if (over) {
317					vxfs_put_page(pp);
318					goto done;
319				}
320			}
321			offset = 0;
322		}
323		vxfs_put_page(pp);
324		offset = 0;
325	}
326
327done:
328	fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
329out:
330	unlock_kernel();
331	return 0;
332}
333