2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * Linux support routines.
14 #include "../afs/param.h"
15 #include "../afs/sysincludes.h"
16 #include "../afs/afsincludes.h"
17 #include "../afs/afs_stats.h"
19 char *crash_addr = 0; /* Induce an oops by writing here. */
21 /* Lookup name and return vnode for same. */
22 int osi_lookupname(char *aname, uio_seg_t seg, int followlink,
23 vnode_t **dirvpp, struct dentry **dpp)
25 struct dentry *dp = NULL;
29 if (seg == AFS_UIOUSER) {
30 dp = followlink ? namei(aname) : lnamei(aname);
33 dp = lookup_dentry(aname, NULL, followlink ? 1 : 0);
36 if (dp && !IS_ERR(dp)) {
48 /* Intialize cache device info and fragment size for disk cache partition. */
49 int osi_InitCacheInfo(char *aname)
53 extern ino_t cacheInode;
54 extern struct osi_dev cacheDev;
55 extern afs_int32 afs_fsfragsize;
56 extern struct super_block *afs_cacheSBp;
58 code = osi_lookupname(aname, AFS_UIOSYS, 1, NULL, &dp);
59 if (code) return ENOENT;
61 cacheInode = dp->d_inode->i_ino;
62 cacheDev.dev = dp->d_inode->i_dev;
63 afs_fsfragsize = dp->d_inode->i_sb->s_blocksize;
64 afs_cacheSBp = dp->d_inode->i_sb;
72 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
73 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
76 * Seek, then read or write to an open inode. addrp points to data in
79 int osi_rdwr(int rw, struct osi_file *file, caddr_t addrp, size_t asize,
84 struct file *filp = &file->file;
85 off_t offset = file->offset;
87 /* Seek to the desired position. Return -1 on error. */
88 if (filp->f_op->llseek) {
89 if (filp->f_op->llseek(filp, (loff_t)offset, 0) != offset)
95 /* Read/Write the data. */
98 code = FOP_READ(filp, addrp, asize);
99 else if (rw == UIO_WRITE)
100 code = FOP_WRITE(filp, addrp, asize);
101 else /* all is well? */
106 *resid = asize - code;
113 /* This variant is called from AFS read/write routines and takes a uio
114 * struct and, if successful, returns 0.
116 int osi_file_uio_rdwr(struct osi_file *osifile, uio_t *uiop, int rw)
118 struct file *filp = &osifile->file;
119 struct inode *ip = FILE_INODE(&osifile->file);
125 if (uiop->uio_seg == AFS_UIOSYS)
128 filp->f_pos = uiop->uio_offset;
129 while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
131 count = iov->iov_len;
139 code = FOP_READ(filp, iov->iov_base, count);
141 code = FOP_WRITE(filp, iov->iov_base, count);
148 iov->iov_base += code;
149 iov->iov_len -= code;
150 uiop->uio_resid -= code;
151 uiop->uio_offset += code;
155 if (uiop->uio_seg == AFS_UIOSYS)
162 * Setup a uio struct.
164 void setup_uio(uio_t *uiop, struct iovec *iovecp, char *buf,
165 int pos, int count, uio_flag_t flag,
168 iovecp->iov_base = buf;
169 iovecp->iov_len = count;
170 uiop->uio_iov = iovecp;
171 uiop->uio_iovcnt = 1;
172 uiop->uio_offset = pos;
174 uiop->uio_resid = count;
175 uiop->uio_flag = flag;
180 * UIO_READ : dp -> uio
181 * UIO_WRITE : uio -> dp
183 int uiomove(char *dp, int length, uio_flag_t rw, uio_t *uiop)
189 while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
191 count = iov->iov_len;
202 switch(uiop->uio_seg) {
206 memcpy(iov->iov_base, dp, count); break;
208 memcpy(dp, iov->iov_base, count); break;
210 printf("uiomove: Bad rw = %d\n", rw);
217 AFS_COPYOUT(dp, iov->iov_base, count, code); break;
219 AFS_COPYIN(iov->iov_base, dp, count, code); break;
221 printf("uiomove: Bad rw = %d\n", rw);
226 printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
232 iov->iov_base += count;
233 iov->iov_len -= count;
234 uiop->uio_offset += count;
235 uiop->uio_resid -= count;
240 void afs_osi_SetTime(osi_timeval_t *tvp)
242 extern int (*sys_settimeofdayp)(struct timeval *tv, struct timezone *tz);
245 AFS_STATCNT(osi_SetTime);
248 (void) (*sys_settimeofdayp)(tvp, NULL);
252 /* Free all the pages on any of the vnodes in the vlru. Must be done before
253 * freeing all memory.
255 void osi_linux_free_inode_pages(void)
260 extern struct vcache *afs_vhashT[VCSIZE];
262 for (i=0; i<VCSIZE; i++) {
263 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
264 ip = (struct inode*)tvc;
266 invalidate_inode_pages(ip);
268 printf("Failed to invalidate all pages on inode 0x%x\n",
276 /* iput an inode. Since we still have a separate inode pool, we don't want
277 * to call iput on AFS inodes, since they would then end up on Linux's
280 void osi_iput(struct inode *ip)
282 extern void afs_delete_inode(struct inode *ip);
283 extern struct vfs *afs_globalVFS;
286 if (ip->i_count == 0 || ip->i_count & 0xffff0000) {
287 osi_Panic("IPUT Bad refCount %d on inode 0x%x\n",
290 if (afs_globalVFS && afs_globalVFS == ip->i_sb ) {
293 afs_delete_inode(ip);
300 /* check_bad_parent() : Checks if this dentry's vcache is a root vcache
301 * that has its mvid (parent dir's fid) pointer set to the wrong directory
302 * due to being mounted in multiple points at once. If so, check_bad_parent()
303 * calls afs_lookup() to correct the vcache's mvid, as well as the volume's
304 * dotdotfid and mtpoint fid members.
306 * dp - dentry to be checked.
310 * This dentry's vcache's mvid will be set to the correct parent directory's
312 * This root vnode's volume will have its dotdotfid and mtpoint fids set
313 * to the correct parent and mountpoint fids.
316 void check_bad_parent(struct dentry *dp)
319 struct vcache *vcp = (struct vcache*)dp->d_inode, *avc = NULL;
320 struct vcache *pvc = (struct vcache *)dp->d_parent->d_inode;
322 if (vcp->mvid->Fid.Volume != pvc->fid.Fid.Volume) { /* bad parent */
326 /* force a lookup, so vcp->mvid is fixed up */
327 afs_lookup(pvc, dp->d_name.name, &avc, credp);
328 if (!avc || vcp != avc) { /* bad, very bad.. */
329 afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
330 "afs_linux_revalidate : bad pointer returned from afs_lookup origvc newvc dentry",
331 ICL_TYPE_POINTER, vcp,
332 ICL_TYPE_POINTER, avc,
333 ICL_TYPE_POINTER, dp);
336 } /* if bad parent */