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_POSITIVE is becoming the default */
32 #ifndef LOOKUP_POSITIVE
33 #define LOOKUP_POSITIVE 0
35 /* Lookup name and return vnode for same. */
37 osi_lookupname_internal(char *aname, int followlink, struct vfsmount **mnt,
42 int flags = LOOKUP_POSITIVE;
46 flags |= LOOKUP_FOLLOW;
47 #if defined(AFS_LINUX26_ENV)
48 code = path_lookup(aname, flags, &nd);
50 if (path_init(aname, flags, &nd))
51 code = path_walk(aname, &nd);
55 *dpp = dget(nd.dentry);
57 *mnt = mntget(nd.mnt);
63 osi_lookupname(char *aname, uio_seg_t seg, int followlink,
69 if (seg == AFS_UIOUSER) {
70 tname = getname(aname);
72 return PTR_ERR(tname);
76 code = osi_lookupname_internal(tname, followlink, NULL, dpp);
77 if (seg == AFS_UIOUSER) {
84 osi_lookupname(char *aname, uio_seg_t seg, int followlink, struct dentry **dpp)
86 struct dentry *dp = NULL;
90 if (seg == AFS_UIOUSER) {
91 dp = followlink ? namei(aname) : lnamei(aname);
93 dp = lookup_dentry(aname, NULL, followlink ? 1 : 0);
96 if (dp && !IS_ERR(dp)) {
108 /* Intialize cache device info and fragment size for disk cache partition. */
110 osi_InitCacheInfo(char *aname)
114 extern ino_t cacheInode;
115 extern struct osi_dev cacheDev;
116 extern afs_int32 afs_fsfragsize;
117 extern struct super_block *afs_cacheSBp;
118 extern struct vfsmount *afs_cacheMnt;
119 code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp);
123 cacheInode = dp->d_inode->i_ino;
124 cacheDev.dev = dp->d_inode->i_sb->s_dev;
125 afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
126 afs_cacheSBp = dp->d_inode->i_sb;
134 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
135 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
138 * seek, then read or write to an open inode. addrp points to data in
142 osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
144 #ifdef AFS_LINUX24_ENV
145 struct file *filp = osifile->filp;
147 struct file *filp = &osifile->file;
153 unsigned long savelim;
155 savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
156 current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
158 if (uiop->uio_seg == AFS_UIOSYS)
161 /* seek to the desired position. Return -1 on error. */
162 if (filp->f_op->llseek) {
163 if (filp->f_op->llseek(filp, (loff_t) uiop->uio_offset, 0) != uiop->uio_offset)
166 filp->f_pos = uiop->uio_offset;
168 while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
170 count = iov->iov_len;
178 code = FOP_READ(filp, iov->iov_base, count);
180 code = FOP_WRITE(filp, iov->iov_base, count);
185 } else if (code == 0) {
187 * This is bad -- we can't read any more data from the
188 * file, but we have no good way of signaling a partial
195 iov->iov_base += code;
196 iov->iov_len -= code;
197 uiop->uio_resid -= code;
198 uiop->uio_offset += code;
202 if (uiop->uio_seg == AFS_UIOSYS)
205 current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
211 * Setup a uio struct.
214 setup_uio(uio_t * uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos,
215 int count, uio_flag_t flag, uio_seg_t seg)
217 iovecp->iov_base = (char *)buf;
218 iovecp->iov_len = count;
219 uiop->uio_iov = iovecp;
220 uiop->uio_iovcnt = 1;
221 uiop->uio_offset = pos;
223 uiop->uio_resid = count;
224 uiop->uio_flag = flag;
229 * UIO_READ : dp -> uio
230 * UIO_WRITE : uio -> dp
233 uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
239 while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
241 count = iov->iov_len;
252 switch (uiop->uio_seg) {
256 memcpy(iov->iov_base, dp, count);
259 memcpy(dp, iov->iov_base, count);
262 printf("uiomove: Bad rw = %d\n", rw);
269 AFS_COPYOUT(dp, iov->iov_base, count, code);
272 AFS_COPYIN(iov->iov_base, dp, count, code);
275 printf("uiomove: Bad rw = %d\n", rw);
280 printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
286 iov->iov_base += count;
287 iov->iov_len -= count;
288 uiop->uio_offset += count;
289 uiop->uio_resid -= count;
295 afs_osi_SetTime(osi_timeval_t * tvp)
297 #if defined(AFS_LINUX24_ENV)
299 #if defined(AFS_LINUX26_ENV)
301 tv.tv_sec = tvp->tv_sec;
302 tv.tv_nsec = tvp->tv_usec * NSEC_PER_USEC;
305 tv.tv_sec = tvp->tv_sec;
306 tv.tv_usec = tvp->tv_usec;
309 AFS_STATCNT(osi_SetTime);
311 do_settimeofday(&tv);
313 extern int (*sys_settimeofdayp) (struct timeval * tv,
314 struct timezone * tz);
318 AFS_STATCNT(osi_SetTime);
321 if (sys_settimeofdayp)
322 (void)(*sys_settimeofdayp) (tvp, NULL);
327 /* Free all the pages on any of the vnodes in the vlru. Must be done before
328 * freeing all memory.
331 osi_linux_free_inode_pages(void)
336 extern struct vcache *afs_vhashT[VCSIZE];
338 for (i = 0; i < VCSIZE; i++) {
339 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
341 #if defined(AFS_LINUX24_ENV)
342 if (ip->i_data.nrpages) {
346 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
347 truncate_inode_pages(&ip->i_data, 0);
348 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)
349 truncate_inode_pages(ip, 0);
351 invalidate_inode_pages(ip);
353 #if defined(AFS_LINUX24_ENV)
354 if (ip->i_data.nrpages) {
358 printf("Failed to invalidate all pages on inode 0x%lx\n",
367 osi_clear_inode(struct inode *ip)
369 cred_t *credp = crref();
370 struct vcache *vcp = ITOAFS(ip);
372 #if defined(AFS_LINUX24_ENV)
373 if (atomic_read(&ip->i_count) > 1)
374 printf("afs_put_inode: ino %ld (0x%lx) has count %ld\n",
375 (long)ip->i_ino, (unsigned long)ip,
376 (long)atomic_read(&ip->i_count));
379 printf("afs_put_inode: ino %ld (0x%lx) has count %ld\n",
380 (long)ip->i_ino, (unsigned long)ip, (long)ip->i_count);
383 afs_InactiveVCache(vcp, credp);
384 ObtainWriteLock(&vcp->lock, 504);
385 ip->i_nlink = 0; /* iput checks this after calling this routine. */
387 ip->i_state = I_CLEAR;
389 ReleaseWriteLock(&vcp->lock);
393 #if !defined(AFS_LINUX26_ENV)
394 /* iput an inode. Since we still have a separate inode pool, we don't want
395 * to call iput on AFS inodes, since they would then end up on Linux's
399 osi_iput(struct inode *ip)
401 extern struct vfs *afs_globalVFS;
405 if (afs_globalVFS && ip->i_sb != afs_globalVFS)
406 osi_Panic("IPUT Not an afs inode\n");
408 #if defined(AFS_LINUX24_ENV)
409 if (atomic_read(&ip->i_count) == 0)
411 if (ip->i_count == 0)
413 osi_Panic("IPUT Bad refCount %d on inode 0x%x\n",
414 #if defined(AFS_LINUX24_ENV)
415 atomic_read(&ip->i_count),
421 #if defined(AFS_LINUX24_ENV)
422 if (atomic_dec_and_test(&ip->i_count))
434 /* check_bad_parent() : Checks if this dentry's vcache is a root vcache
435 * that has its mvid (parent dir's fid) pointer set to the wrong directory
436 * due to being mounted in multiple points at once. If so, check_bad_parent()
437 * calls afs_lookup() to correct the vcache's mvid, as well as the volume's
438 * dotdotfid and mtpoint fid members.
440 * dp - dentry to be checked.
444 * This dentry's vcache's mvid will be set to the correct parent directory's
446 * This root vnode's volume will have its dotdotfid and mtpoint fids set
447 * to the correct parent and mountpoint fids.
451 check_bad_parent(struct dentry *dp)
454 struct vcache *vcp = ITOAFS(dp->d_inode), *avc = NULL;
455 struct vcache *pvc = ITOAFS(dp->d_parent->d_inode);
457 if (vcp->mvid->Fid.Volume != pvc->fid.Fid.Volume) { /* bad parent */
461 /* force a lookup, so vcp->mvid is fixed up */
462 afs_lookup(pvc, dp->d_name.name, &avc, credp);
463 if (!avc || vcp != avc) { /* bad, very bad.. */
464 afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
465 "check_bad_parent: bad pointer returned from afs_lookup origvc newvc dentry",
466 ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, avc,
467 ICL_TYPE_POINTER, dp);
477 struct task_struct *rxk_ListenerTask;
483 sigfillset(¤t->blocked);
484 RECALC_SIGPENDING(current);
489 osi_linux_rxkreg(void)
491 rxk_ListenerTask = current;