09b3f22855dd69f44cc4b9462b089486dd25d509
[openafs.git] / src / afs / LINUX / osi_misc.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * Linux support routines.
12  *
13  */
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17 RCSID
18     ("$Header$");
19
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"
25 #endif
26 #if defined(AFS_LINUX26_ENV)
27 #include "h/namei.h"
28 #endif
29
30 #if defined(AFS_LINUX24_ENV)
31 /* LOOKUP_POSITIVE is becoming the default */
32 #ifndef LOOKUP_POSITIVE
33 #define LOOKUP_POSITIVE 0
34 #endif
35 /* Lookup name and return vnode for same. */
36 int
37 osi_lookupname_internal(char *aname, int followlink, struct vfsmount **mnt,
38                         struct dentry **dpp)
39 {
40     int code;
41     struct nameidata nd;
42     int flags = LOOKUP_POSITIVE;
43     code = ENOENT;
44
45     if (followlink)
46        flags |= LOOKUP_FOLLOW;
47 #if defined(AFS_LINUX26_ENV)
48     code = path_lookup(aname, flags, &nd);
49 #else
50     if (path_init(aname, flags, &nd))
51         code = path_walk(aname, &nd);
52 #endif
53
54     if (!code) {
55         *dpp = dget(nd.dentry);
56         if (mnt)
57            *mnt = mntget(nd.mnt);
58         path_release(&nd);
59     }
60     return code;
61 }
62 int
63 osi_lookupname(char *aname, uio_seg_t seg, int followlink, 
64                         struct dentry **dpp)
65 {
66     int code;
67     char *tname;
68     code = ENOENT;
69     if (seg == AFS_UIOUSER) {
70         tname = getname(aname);
71         if (IS_ERR(tname)) 
72             return PTR_ERR(tname);
73     } else {
74         tname = aname;
75     }
76     code = osi_lookupname_internal(tname, followlink, NULL, dpp);   
77     if (seg == AFS_UIOUSER) {
78         putname(tname);
79     }
80     return code;
81 }
82 #else
83 int
84 osi_lookupname(char *aname, uio_seg_t seg, int followlink, struct dentry **dpp)
85 {
86     struct dentry *dp = NULL;
87     int code;
88
89     code = ENOENT;
90     if (seg == AFS_UIOUSER) {
91         dp = followlink ? namei(aname) : lnamei(aname);
92     } else {
93         dp = lookup_dentry(aname, NULL, followlink ? 1 : 0);
94     }
95
96     if (dp && !IS_ERR(dp)) {
97         if (dp->d_inode) {
98             *dpp = dp;
99             code = 0;
100         } else
101             dput(dp);
102     }
103
104     return code;
105 }
106 #endif
107
108 /* Intialize cache device info and fragment size for disk cache partition. */
109 int
110 osi_InitCacheInfo(char *aname)
111 {
112     int code;
113     struct dentry *dp;
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);
120     if (code)
121         return ENOENT;
122
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;
127
128     dput(dp);
129
130     return 0;
131 }
132
133
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)
136
137 /* osi_rdwr
138  * seek, then read or write to an open inode. addrp points to data in
139  * kernel space.
140  */
141 int
142 osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
143 {
144 #ifdef AFS_LINUX26_ENV
145     struct file *filp = osifile->filp;
146 #else
147     struct file *filp = &osifile->file;
148 #endif
149     KERNEL_SPACE_DECL;
150     int code = 0;
151     struct iovec *iov;
152     afs_size_t count;
153     unsigned long savelim;
154
155     savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
156     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
157
158     if (uiop->uio_seg == AFS_UIOSYS)
159         TO_USER_SPACE();
160
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)
164             return -1;
165     } else
166         filp->f_pos = uiop->uio_offset;
167
168     while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
169         iov = uiop->uio_iov;
170         count = iov->iov_len;
171         if (count == 0) {
172             uiop->uio_iov++;
173             uiop->uio_iovcnt--;
174             continue;
175         }
176
177         if (rw == UIO_READ)
178             code = FOP_READ(filp, iov->iov_base, count);
179         else
180             code = FOP_WRITE(filp, iov->iov_base, count);
181
182         if (code < 0) {
183             code = -code;
184             break;
185         } else if (code == 0) {
186             /*
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
189              * read either.
190              */
191             code = EIO;
192             break;
193         }
194
195         iov->iov_base += code;
196         iov->iov_len -= code;
197         uiop->uio_resid -= code;
198         uiop->uio_offset += code;
199         code = 0;
200     }
201
202     if (uiop->uio_seg == AFS_UIOSYS)
203         TO_KERNEL_SPACE();
204
205     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
206
207     return code;
208 }
209
210 /* setup_uio 
211  * Setup a uio struct.
212  */
213 void
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)
216 {
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;
222     uiop->uio_seg = seg;
223     uiop->uio_resid = count;
224     uiop->uio_flag = flag;
225 }
226
227
228 /* uiomove
229  * UIO_READ : dp -> uio
230  * UIO_WRITE : uio -> dp
231  */
232 int
233 uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
234 {
235     int count;
236     struct iovec *iov;
237     int code;
238
239     while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
240         iov = uiop->uio_iov;
241         count = iov->iov_len;
242
243         if (!count) {
244             uiop->uio_iov++;
245             uiop->uio_iovcnt--;
246             continue;
247         }
248
249         if (count > length)
250             count = length;
251
252         switch (uiop->uio_seg) {
253         case AFS_UIOSYS:
254             switch (rw) {
255             case UIO_READ:
256                 memcpy(iov->iov_base, dp, count);
257                 break;
258             case UIO_WRITE:
259                 memcpy(dp, iov->iov_base, count);
260                 break;
261             default:
262                 printf("uiomove: Bad rw = %d\n", rw);
263                 return -EINVAL;
264             }
265             break;
266         case AFS_UIOUSER:
267             switch (rw) {
268             case UIO_READ:
269                 AFS_COPYOUT(dp, iov->iov_base, count, code);
270                 break;
271             case UIO_WRITE:
272                 AFS_COPYIN(iov->iov_base, dp, count, code);
273                 break;
274             default:
275                 printf("uiomove: Bad rw = %d\n", rw);
276                 return -EINVAL;
277             }
278             break;
279         default:
280             printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
281             return -EINVAL;
282         }
283
284         dp += count;
285         length -= count;
286         iov->iov_base += count;
287         iov->iov_len -= count;
288         uiop->uio_offset += count;
289         uiop->uio_resid -= count;
290     }
291     return 0;
292 }
293
294 void
295 afs_osi_SetTime(osi_timeval_t * tvp)
296 {
297 #if defined(AFS_LINUX24_ENV)
298
299 #if defined(AFS_LINUX26_ENV)
300     struct timespec tv;
301     tv.tv_sec = tvp->tv_sec;
302     tv.tv_nsec = tvp->tv_usec * NSEC_PER_USEC;
303 #else
304     struct timeval tv;
305     tv.tv_sec = tvp->tv_sec;
306     tv.tv_usec = tvp->tv_usec;
307 #endif
308
309     AFS_STATCNT(osi_SetTime);
310
311     do_settimeofday(&tv);
312 #else
313     extern int (*sys_settimeofdayp) (struct timeval * tv,
314                                      struct timezone * tz);
315
316     KERNEL_SPACE_DECL;
317
318     AFS_STATCNT(osi_SetTime);
319
320     TO_USER_SPACE();
321     if (sys_settimeofdayp)
322         (void)(*sys_settimeofdayp) (tvp, NULL);
323     TO_KERNEL_SPACE();
324 #endif
325 }
326
327 /* osi_linux_free_inode_pages
328  *
329  * Free all vnodes remaining in the afs hash.  Must be done before
330  * shutting down afs and freeing all memory.
331  */
332 void
333 osi_linux_free_inode_pages(void)
334 {
335     int i;
336     struct vcache *tvc, *nvc;
337     extern struct vcache *afs_vhashT[VCSIZE];
338
339     for (i = 0; i < VCSIZE; i++) {
340         for (tvc = afs_vhashT[i]; tvc; ) {
341             int slept;
342         
343             nvc = tvc->hnext;
344             if (afs_FlushVCache(tvc, &slept))           /* slept always 0 for linux? */
345                 printf("Failed to invalidate all pages on inode 0x%p\n", tvc);
346             tvc = nvc;
347         }
348     }
349 }
350
351 struct task_struct *rxk_ListenerTask;
352
353 void
354 osi_linux_mask(void)
355 {
356     SIG_LOCK(current);
357     sigfillset(&current->blocked);
358     RECALC_SIGPENDING(current);
359     SIG_UNLOCK(current);
360 }
361
362 void
363 osi_linux_rxkreg(void)
364 {
365     rxk_ListenerTask = current;
366 }