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"
20 #include "afs/sysincludes.h"
21 #include "afsincludes.h"
22 #include "afs/afs_stats.h"
23 #if defined(AFS_LINUX24_ENV)
24 #include "h/smp_lock.h"
26 #if defined(AFS_LINUX26_ENV)
30 #if defined(AFS_LINUX24_ENV)
31 /* Lookup name and return vnode for same. */
33 osi_lookupname(char *aname, uio_seg_t seg, int followlink,
34 vnode_t ** dirvpp, struct dentry **dpp)
37 extern struct nameidata afs_cacheNd;
38 struct nameidata *nd = &afs_cacheNd;
41 if (seg == AFS_UIOUSER) {
43 followlink ? user_path_walk(aname,
44 nd) : user_path_walk_link(aname, nd);
46 #if defined(AFS_LINUX26_ENV)
47 code = path_lookup(aname, followlink ? LOOKUP_FOLLOW : 0, nd);
49 if (path_init(aname, followlink ? LOOKUP_FOLLOW : 0, nd))
50 code = path_walk(aname, nd);
55 if (nd->dentry->d_inode) {
56 *dpp = dget(nd->dentry);
67 osi_lookupname(char *aname, uio_seg_t seg, int followlink, vnode_t ** dirvpp,
70 struct dentry *dp = NULL;
74 if (seg == AFS_UIOUSER) {
75 dp = followlink ? namei(aname) : lnamei(aname);
77 dp = lookup_dentry(aname, NULL, followlink ? 1 : 0);
80 if (dp && !IS_ERR(dp)) {
92 /* Intialize cache device info and fragment size for disk cache partition. */
94 osi_InitCacheInfo(char *aname)
98 extern ino_t cacheInode;
99 extern struct osi_dev cacheDev;
100 extern afs_int32 afs_fsfragsize;
101 extern struct super_block *afs_cacheSBp;
102 code = osi_lookupname(aname, AFS_UIOSYS, 1, NULL, &dp);
106 cacheInode = dp->d_inode->i_ino;
107 cacheDev.dev = dp->d_inode->i_sb->s_dev;
108 afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
109 afs_cacheSBp = dp->d_inode->i_sb;
117 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
118 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
121 * Seek, then read or write to an open inode. addrp points to data in
125 osi_rdwr(int rw, struct osi_file *file, caddr_t addrp, size_t asize,
130 struct file *filp = &file->file;
131 off_t offset = file->offset;
132 unsigned long savelim;
134 /* Seek to the desired position. Return -1 on error. */
135 if (filp->f_op->llseek) {
136 if (filp->f_op->llseek(filp, (loff_t) offset, 0) != offset)
139 filp->f_pos = offset;
141 savelim = current->rlim[RLIMIT_FSIZE].rlim_cur;
142 current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
144 /* Read/Write the data. */
147 code = FOP_READ(filp, addrp, asize);
148 else if (rw == UIO_WRITE)
149 code = FOP_WRITE(filp, addrp, asize);
150 else /* all is well? */
154 current->rlim[RLIMIT_FSIZE].rlim_cur = savelim;
157 *resid = asize - code;
163 /* This variant is called from AFS read/write routines and takes a uio
164 * struct and, if successful, returns 0.
167 osi_file_uio_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
169 struct file *filp = &osifile->file;
170 struct inode *ip = FILE_INODE(&osifile->file);
175 unsigned long savelim;
177 savelim = current->rlim[RLIMIT_FSIZE].rlim_cur;
178 current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
180 if (uiop->uio_seg == AFS_UIOSYS)
183 filp->f_pos = uiop->uio_offset;
184 while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
186 count = iov->iov_len;
194 code = FOP_READ(filp, iov->iov_base, count);
196 code = FOP_WRITE(filp, iov->iov_base, count);
201 } else if (code == 0) {
203 * This is bad -- we can't read any more data from the
204 * file, but we have no good way of signaling a partial
211 iov->iov_base += code;
212 iov->iov_len -= code;
213 uiop->uio_resid -= code;
214 uiop->uio_offset += code;
218 if (uiop->uio_seg == AFS_UIOSYS)
221 current->rlim[RLIMIT_FSIZE].rlim_cur = savelim;
227 * Setup a uio struct.
230 setup_uio(uio_t * uiop, struct iovec *iovecp, char *buf, afs_offs_t pos,
231 int count, uio_flag_t flag, uio_seg_t seg)
233 iovecp->iov_base = buf;
234 iovecp->iov_len = count;
235 uiop->uio_iov = iovecp;
236 uiop->uio_iovcnt = 1;
237 uiop->uio_offset = pos;
239 uiop->uio_resid = count;
240 uiop->uio_flag = flag;
245 * UIO_READ : dp -> uio
246 * UIO_WRITE : uio -> dp
249 uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
255 while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
257 count = iov->iov_len;
268 switch (uiop->uio_seg) {
272 memcpy(iov->iov_base, dp, count);
275 memcpy(dp, iov->iov_base, count);
278 printf("uiomove: Bad rw = %d\n", rw);
285 AFS_COPYOUT(dp, iov->iov_base, count, code);
288 AFS_COPYIN(iov->iov_base, dp, count, code);
291 printf("uiomove: Bad rw = %d\n", rw);
296 printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
302 iov->iov_base += count;
303 iov->iov_len -= count;
304 uiop->uio_offset += count;
305 uiop->uio_resid -= count;
311 afs_osi_SetTime(osi_timeval_t * tvp)
313 #if defined(AFS_LINUX24_ENV)
315 #if defined(AFS_LINUX26_ENV)
317 tv.tv_sec = tvp->tv_sec;
318 tv.tv_nsec = tvp->tv_usec * NSEC_PER_USEC;
321 tv.tv_sec = tvp->tv_sec;
322 tv.tv_usec = tvp->tv_usec;
325 AFS_STATCNT(osi_SetTime);
327 do_settimeofday(&tv);
329 extern int (*sys_settimeofdayp) (struct timeval * tv,
330 struct timezone * tz);
334 AFS_STATCNT(osi_SetTime);
337 if (sys_settimeofdayp)
338 (void)(*sys_settimeofdayp) (tvp, NULL);
343 /* Free all the pages on any of the vnodes in the vlru. Must be done before
344 * freeing all memory.
347 osi_linux_free_inode_pages(void)
352 extern struct vcache *afs_vhashT[VCSIZE];
354 for (i = 0; i < VCSIZE; i++) {
355 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
357 #if defined(AFS_LINUX24_ENV)
358 if (ip->i_data.nrpages) {
362 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
363 truncate_inode_pages(&ip->i_data, 0);
364 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)
365 truncate_inode_pages(ip, 0);
367 invalidate_inode_pages(ip);
369 #if defined(AFS_LINUX24_ENV)
370 if (ip->i_data.nrpages) {
374 printf("Failed to invalidate all pages on inode 0x%x\n",
383 osi_clear_inode(struct inode *ip)
385 cred_t *credp = crref();
386 struct vcache *vcp = ITOAFS(ip);
388 #if defined(AFS_LINUX24_ENV)
389 if (atomic_read(&ip->i_count) > 1)
393 printf("afs_put_inode: ino %d (0x%x) has count %d\n", ip->i_ino, ip,
396 afs_InactiveVCache(vcp, credp);
397 ObtainWriteLock(&vcp->lock, 504);
398 ip->i_nlink = 0; /* iput checks this after calling this routine. */
399 ip->i_state = I_CLEAR;
400 ReleaseWriteLock(&vcp->lock);
404 #if !defined(AFS_LINUX26_ENV)
405 /* iput an inode. Since we still have a separate inode pool, we don't want
406 * to call iput on AFS inodes, since they would then end up on Linux's
410 osi_iput(struct inode *ip)
412 extern struct vfs *afs_globalVFS;
416 if (afs_globalVFS && ip->i_sb != afs_globalVFS)
417 osi_Panic("IPUT Not an afs inode\n");
419 #if defined(AFS_LINUX24_ENV)
420 if (atomic_read(&ip->i_count) == 0)
422 if (ip->i_count == 0)
424 osi_Panic("IPUT Bad refCount %d on inode 0x%x\n",
425 #if defined(AFS_LINUX24_ENV)
426 atomic_read(&ip->i_count),
432 #if defined(AFS_LINUX24_ENV)
433 if (atomic_dec_and_test(&ip->i_count))
445 /* check_bad_parent() : Checks if this dentry's vcache is a root vcache
446 * that has its mvid (parent dir's fid) pointer set to the wrong directory
447 * due to being mounted in multiple points at once. If so, check_bad_parent()
448 * calls afs_lookup() to correct the vcache's mvid, as well as the volume's
449 * dotdotfid and mtpoint fid members.
451 * dp - dentry to be checked.
455 * This dentry's vcache's mvid will be set to the correct parent directory's
457 * This root vnode's volume will have its dotdotfid and mtpoint fids set
458 * to the correct parent and mountpoint fids.
462 check_bad_parent(struct dentry *dp)
465 struct vcache *vcp = ITOAFS(dp->d_inode), *avc = NULL;
466 struct vcache *pvc = ITOAFS(dp->d_parent->d_inode);
468 if (vcp->mvid->Fid.Volume != pvc->fid.Fid.Volume) { /* bad parent */
472 /* force a lookup, so vcp->mvid is fixed up */
473 afs_lookup(pvc, dp->d_name.name, &avc, credp);
474 if (!avc || vcp != avc) { /* bad, very bad.. */
475 afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
476 "check_bad_parent: bad pointer returned from afs_lookup origvc newvc dentry",
477 ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, avc,
478 ICL_TYPE_POINTER, dp);
488 struct task_struct *rxk_ListenerTask;
494 sigfillset(¤t->blocked);
495 RECALC_SIGPENDING(current);
500 osi_linux_rxkreg(void)
502 rxk_ListenerTask = current;