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 <afsconfig.h>
15 #include "../afs/param.h"
19 #include "../afs/sysincludes.h"
20 #include "../afs/afsincludes.h"
21 #include "../afs/afs_stats.h"
22 #if defined(AFS_LINUX24_ENV)
23 #include "../h/smp_lock.h"
26 char *crash_addr = 0; /* Induce an oops by writing here. */
28 /* Lookup name and return vnode for same. */
29 int osi_lookupname(char *aname, uio_seg_t seg, int followlink,
30 vnode_t **dirvpp, struct dentry **dpp)
32 #if defined(AFS_LINUX24_ENV)
35 struct dentry *dp = NULL;
40 #if defined(AFS_LINUX24_ENV)
41 if (seg == AFS_UIOUSER) {
43 user_path_walk(aname, &nd) : user_path_walk_link(aname, &nd);
46 if (path_init(aname, followlink ? LOOKUP_FOLLOW : 0, &nd))
47 code = path_walk(aname, &nd);
51 if (nd.dentry->d_inode) {
52 *dpp = dget(nd.dentry);
58 if (seg == AFS_UIOUSER) {
59 dp = followlink ? namei(aname) : lnamei(aname);
62 dp = lookup_dentry(aname, NULL, followlink ? 1 : 0);
65 if (dp && !IS_ERR(dp)) {
78 /* Intialize cache device info and fragment size for disk cache partition. */
79 int osi_InitCacheInfo(char *aname)
83 extern ino_t cacheInode;
84 extern struct osi_dev cacheDev;
85 extern afs_int32 afs_fsfragsize;
86 extern struct super_block *afs_cacheSBp;
88 code = osi_lookupname(aname, AFS_UIOSYS, 1, NULL, &dp);
89 if (code) return ENOENT;
91 cacheInode = dp->d_inode->i_ino;
92 cacheDev.dev = dp->d_inode->i_dev;
93 afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
94 afs_cacheSBp = dp->d_inode->i_sb;
102 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
103 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
106 * Seek, then read or write to an open inode. addrp points to data in
109 int osi_rdwr(int rw, struct osi_file *file, caddr_t addrp, size_t asize,
114 struct file *filp = &file->file;
115 off_t offset = file->offset;
117 /* Seek to the desired position. Return -1 on error. */
118 if (filp->f_op->llseek) {
119 if (filp->f_op->llseek(filp, (loff_t)offset, 0) != offset)
123 filp->f_pos = offset;
125 /* Read/Write the data. */
128 code = FOP_READ(filp, addrp, asize);
129 else if (rw == UIO_WRITE)
130 code = FOP_WRITE(filp, addrp, asize);
131 else /* all is well? */
136 *resid = asize - code;
143 /* This variant is called from AFS read/write routines and takes a uio
144 * struct and, if successful, returns 0.
146 int osi_file_uio_rdwr(struct osi_file *osifile, uio_t *uiop, int rw)
148 struct file *filp = &osifile->file;
149 struct inode *ip = FILE_INODE(&osifile->file);
155 if (uiop->uio_seg == AFS_UIOSYS)
158 filp->f_pos = uiop->uio_offset;
159 while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
161 count = iov->iov_len;
169 code = FOP_READ(filp, iov->iov_base, count);
171 code = FOP_WRITE(filp, iov->iov_base, count);
178 iov->iov_base += code;
179 iov->iov_len -= code;
180 uiop->uio_resid -= code;
181 uiop->uio_offset += code;
185 if (uiop->uio_seg == AFS_UIOSYS)
192 * Setup a uio struct.
194 void setup_uio(uio_t *uiop, struct iovec *iovecp, char *buf,
195 afs_offs_t pos, int count, uio_flag_t flag,
198 iovecp->iov_base = buf;
199 iovecp->iov_len = count;
200 uiop->uio_iov = iovecp;
201 uiop->uio_iovcnt = 1;
202 uiop->uio_offset = pos;
204 uiop->uio_resid = count;
205 uiop->uio_flag = flag;
210 * UIO_READ : dp -> uio
211 * UIO_WRITE : uio -> dp
213 int uiomove(char *dp, int length, uio_flag_t rw, uio_t *uiop)
219 while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
221 count = iov->iov_len;
232 switch(uiop->uio_seg) {
236 memcpy(iov->iov_base, dp, count); break;
238 memcpy(dp, iov->iov_base, count); break;
240 printf("uiomove: Bad rw = %d\n", rw);
247 AFS_COPYOUT(dp, iov->iov_base, count, code); break;
249 AFS_COPYIN(iov->iov_base, dp, count, code); break;
251 printf("uiomove: Bad rw = %d\n", rw);
256 printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
262 iov->iov_base += count;
263 iov->iov_len -= count;
264 uiop->uio_offset += count;
265 uiop->uio_resid -= count;
270 void afs_osi_SetTime(osi_timeval_t *tvp)
272 extern int (*sys_settimeofdayp)(struct timeval *tv, struct timezone *tz);
273 #ifdef AFS_LINUX_64BIT_KERNEL
275 AFS_STATCNT(osi_SetTime);
276 tv.tv_sec = tvp->tv_sec;
277 tv.tv_usec = tvp->tv_usec;
278 (void) (*sys_settimeofdayp)(&tv, NULL);
282 AFS_STATCNT(osi_SetTime);
285 (void) (*sys_settimeofdayp)(tvp, NULL);
290 /* Free all the pages on any of the vnodes in the vlru. Must be done before
291 * freeing all memory.
293 void osi_linux_free_inode_pages(void)
298 extern struct vcache *afs_vhashT[VCSIZE];
300 for (i=0; i<VCSIZE; i++) {
301 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
302 ip = (struct inode*)tvc;
303 #if defined(AFS_LINUX24_ENV)
304 if (ip->i_data.nrpages) {
308 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
309 truncate_inode_pages(&ip->i_data, 0);
310 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)
311 truncate_inode_pages(ip, 0);
313 invalidate_inode_pages(ip);
315 #if defined(AFS_LINUX24_ENV)
316 if (ip->i_data.nrpages) {
320 printf("Failed to invalidate all pages on inode 0x%x\n",
328 void osi_clear_inode(struct inode *ip)
330 cred_t *credp = crref();
331 struct vcache *vc = (struct vcache*)ip;
333 #if defined(AFS_LINUX24_ENV)
334 if (atomic_read(&ip->i_count) > 1)
338 printf("afs_put_inode: ino %d (0x%x) has count %d\n", ip->i_ino, ip);
340 ObtainWriteLock(&vc->lock, 504);
341 afs_InactiveVCache(vc, credp);
342 ReleaseWriteLock(&vc->lock);
343 #if defined(AFS_LINUX24_ENV)
344 atomic_set(&ip->i_count, 0);
348 ip->i_nlink = 0; /* iput checks this after calling this routine. */
352 /* iput an inode. Since we still have a separate inode pool, we don't want
353 * to call iput on AFS inodes, since they would then end up on Linux's
356 void osi_iput(struct inode *ip)
358 extern struct vfs *afs_globalVFS;
361 #if defined(AFS_LINUX24_ENV)
362 if (atomic_read(&ip->i_count) == 0 || atomic_read(&ip->i_count) & 0xffff0000) {
364 if (ip->i_count == 0 || ip->i_count & 0xffff0000) {
366 osi_Panic("IPUT Bad refCount %d on inode 0x%x\n",
367 #if defined(AFS_LINUX24_ENV)
368 atomic_read(&ip->i_count), ip);
373 if (afs_globalVFS && afs_globalVFS == ip->i_sb ) {
374 #if defined(AFS_LINUX24_ENV)
375 atomic_dec(&ip->i_count);
376 if (!atomic_read(&ip->i_count))
388 /* check_bad_parent() : Checks if this dentry's vcache is a root vcache
389 * that has its mvid (parent dir's fid) pointer set to the wrong directory
390 * due to being mounted in multiple points at once. If so, check_bad_parent()
391 * calls afs_lookup() to correct the vcache's mvid, as well as the volume's
392 * dotdotfid and mtpoint fid members.
394 * dp - dentry to be checked.
398 * This dentry's vcache's mvid will be set to the correct parent directory's
400 * This root vnode's volume will have its dotdotfid and mtpoint fids set
401 * to the correct parent and mountpoint fids.
404 void check_bad_parent(struct dentry *dp)
407 struct vcache *vcp = (struct vcache*)dp->d_inode, *avc = NULL;
408 struct vcache *pvc = (struct vcache *)dp->d_parent->d_inode;
410 if (vcp->mvid->Fid.Volume != pvc->fid.Fid.Volume) { /* bad parent */
414 /* force a lookup, so vcp->mvid is fixed up */
415 afs_lookup(pvc, dp->d_name.name, &avc, credp);
416 if (!avc || vcp != avc) { /* bad, very bad.. */
417 afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
418 "afs_linux_revalidate : bad pointer returned from afs_lookup origvc newvc dentry",
419 ICL_TYPE_POINTER, vcp,
420 ICL_TYPE_POINTER, avc,
421 ICL_TYPE_POINTER, dp);
426 } /* if bad parent */