1 /* Copyright 1998 Transarc Corporation - All Rights Reserved.
5 * Linux support routines.
8 #include "../afs/param.h"
9 #include "../afs/sysincludes.h"
10 #include "../afs/afsincludes.h"
11 #include "../afs/afs_stats.h"
13 char *crash_addr = 0; /* Induce an oops by writing here. */
15 /* Lookup name and return vnode for same. */
16 int osi_lookupname(char *aname, uio_seg_t seg, int followlink,
17 vnode_t **dirvpp, struct dentry **dpp)
19 struct dentry *dp = NULL;
23 if (seg == AFS_UIOUSER) {
24 dp = followlink ? namei(aname) : lnamei(aname);
27 dp = lookup_dentry(aname, NULL, followlink ? 1 : 0);
30 if (dp && !IS_ERR(dp)) {
42 /* Intialize cache device info and fragment size for disk cache partition. */
43 int osi_InitCacheInfo(char *aname)
47 extern ino_t cacheInode;
48 extern struct osi_dev cacheDev;
49 extern afs_int32 afs_fsfragsize;
50 extern struct super_block *afs_cacheSBp;
52 code = osi_lookupname(aname, AFS_UIOSYS, 1, NULL, &dp);
53 if (code) return ENOENT;
55 cacheInode = dp->d_inode->i_ino;
56 cacheDev.dev = dp->d_inode->i_dev;
57 afs_fsfragsize = dp->d_inode->i_sb->s_blocksize;
58 afs_cacheSBp = dp->d_inode->i_sb;
66 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
67 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
70 * Seek, then read or write to an open inode. addrp points to data in
73 int osi_rdwr(int rw, struct osi_file *file, caddr_t addrp, size_t asize,
78 struct file *filp = &file->file;
79 off_t offset = file->offset;
81 /* Seek to the desired position. Return -1 on error. */
82 if (filp->f_op->llseek) {
83 if (filp->f_op->llseek(filp, (loff_t)offset, 0) != offset)
89 /* Read/Write the data. */
92 code = FOP_READ(filp, addrp, asize);
93 else if (rw == UIO_WRITE)
94 code = FOP_WRITE(filp, addrp, asize);
95 else /* all is well? */
100 *resid = asize - code;
107 /* This variant is called from AFS read/write routines and takes a uio
108 * struct and, if successful, returns 0.
110 int osi_file_uio_rdwr(struct osi_file *osifile, uio_t *uiop, int rw)
112 struct file *filp = &osifile->file;
113 struct inode *ip = FILE_INODE(&osifile->file);
119 if (uiop->uio_seg == AFS_UIOSYS)
122 filp->f_pos = uiop->uio_offset;
123 while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
125 count = iov->iov_len;
133 code = FOP_READ(filp, iov->iov_base, count);
135 code = FOP_WRITE(filp, iov->iov_base, count);
142 iov->iov_base += code;
143 iov->iov_len -= code;
144 uiop->uio_resid -= code;
145 uiop->uio_offset += code;
149 if (uiop->uio_seg == AFS_UIOSYS)
156 * Setup a uio struct.
158 void setup_uio(uio_t *uiop, struct iovec *iovecp, char *buf,
159 int pos, int count, uio_flag_t flag,
162 iovecp->iov_base = buf;
163 iovecp->iov_len = count;
164 uiop->uio_iov = iovecp;
165 uiop->uio_iovcnt = 1;
166 uiop->uio_offset = pos;
168 uiop->uio_resid = count;
169 uiop->uio_flag = flag;
174 * UIO_READ : dp -> uio
175 * UIO_WRITE : uio -> dp
177 int uiomove(char *dp, int length, uio_flag_t rw, uio_t *uiop)
183 while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
185 count = iov->iov_len;
196 switch(uiop->uio_seg) {
200 memcpy(iov->iov_base, dp, count); break;
202 memcpy(dp, iov->iov_base, count); break;
204 printf("uiomove: Bad rw = %d\n", rw);
211 AFS_COPYOUT(dp, iov->iov_base, count, code); break;
213 AFS_COPYIN(iov->iov_base, dp, count, code); break;
215 printf("uiomove: Bad rw = %d\n", rw);
220 printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
226 iov->iov_base += count;
227 iov->iov_len -= count;
228 uiop->uio_offset += count;
229 uiop->uio_resid -= count;
234 void afs_osi_SetTime(osi_timeval_t *tvp)
236 extern int (*sys_settimeofdayp)(struct timeval *tv, struct timezone *tz);
239 AFS_STATCNT(osi_SetTime);
242 (void) (*sys_settimeofdayp)(tvp, NULL);
246 /* Free all the pages on any of the vnodes in the vlru. Must be done before
247 * freeing all memory.
249 void osi_linux_free_inode_pages(void)
254 extern struct vcache *afs_vhashT[VCSIZE];
256 for (i=0; i<VCSIZE; i++) {
257 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
258 ip = (struct inode*)tvc;
260 invalidate_inode_pages(ip);
262 printf("Failed to invalidate all pages on inode 0x%x\n",
270 /* iput an inode. Since we still have a separate inode pool, we don't want
271 * to call iput on AFS inodes, since they would then end up on Linux's
274 void osi_iput(struct inode *ip)
276 extern void afs_delete_inode(struct inode *ip);
277 extern struct vfs *afs_globalVFS;
280 if (ip->i_count == 0 || ip->i_count & 0xffff0000) {
281 osi_Panic("IPUT Bad refCount %d on inode 0x%x\n",
284 if (afs_globalVFS && afs_globalVFS == ip->i_sb ) {
287 afs_delete_inode(ip);
294 /* check_bad_parent() : Checks if this dentry's vcache is a root vcache
295 * that has its mvid (parent dir's fid) pointer set to the wrong directory
296 * due to being mounted in multiple points at once. If so, check_bad_parent()
297 * calls afs_lookup() to correct the vcache's mvid, as well as the volume's
298 * dotdotfid and mtpoint fid members.
300 * dp - dentry to be checked.
304 * This dentry's vcache's mvid will be set to the correct parent directory's
306 * This root vnode's volume will have its dotdotfid and mtpoint fids set
307 * to the correct parent and mountpoint fids.
310 void check_bad_parent(struct dentry *dp)
313 struct vcache *vcp = (struct vcache*)dp->d_inode, *avc = NULL;
314 struct vcache *pvc = (struct vcache *)dp->d_parent->d_inode;
316 if (vcp->mvid->Fid.Volume != pvc->fid.Fid.Volume) { /* bad parent */
320 /* force a lookup, so vcp->mvid is fixed up */
321 afs_lookup(pvc, dp->d_name.name, &avc, credp);
322 if (!avc || vcp != avc) { /* bad, very bad.. */
323 afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
324 "afs_linux_revalidate : bad pointer returned from afs_lookup origvc newvc dentry",
325 ICL_TYPE_POINTER, vcp,
326 ICL_TYPE_POINTER, avc,
327 ICL_TYPE_POINTER, dp);
330 } /* if bad parent */