35bd031d00bd96afbb23ad0cd1dd5e37fc96759c
[openafs.git] / src / afs / LINUX24 / osi_file.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 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #ifdef AFS_LINUX24_ENV
15 #include "h/module.h" /* early to avoid printf->printk mapping */
16 #endif
17 #include "afs/sysincludes.h"    /* Standard vendor system headers */
18 #include "afsincludes.h"        /* Afs-based standard headers */
19 #include "afs/afs_stats.h"      /* afs statistics */
20 #include "h/smp_lock.h"
21
22 afs_lock_t afs_xosi;            /* lock is for tvattr */
23 extern struct osi_dev cacheDev;
24 #if defined(AFS_LINUX24_ENV)
25 extern struct vfsmount *afs_cacheMnt;
26 #endif
27 extern struct super_block *afs_cacheSBp;
28
29 void *
30 osi_UFSOpen(afs_dcache_id_t *ainode)
31 {
32     struct osi_file *afile = NULL;
33     extern int cacheDiskType;
34     afs_int32 code = 0;
35     struct inode *tip = NULL;
36     struct file *filp = NULL;
37     AFS_STATCNT(osi_UFSOpen);
38     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
39         osi_Panic("UFSOpen called for non-UFS cache\n");
40     }
41     if (!afs_osicred_initialized) {
42         /* valid for alpha_osf, SunOS, Ultrix */
43         memset(&afs_osi_cred, 0, sizeof(afs_ucred_t));
44         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
45         afs_osicred_initialized = 1;
46     }
47     afile = (struct osi_file *)osi_AllocLargeSpace(sizeof(struct osi_file));
48     AFS_GUNLOCK();
49     if (!afile) {
50         osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n",
51                   sizeof(struct osi_file));
52     }
53     memset(afile, 0, sizeof(struct osi_file));
54     filp = &afile->file;
55     filp->f_dentry = &afile->dentry;
56     tip = iget(afs_cacheSBp, ainode->ufs);
57     if (!tip)
58         osi_Panic("Can't get inode %d\n", ainode->ufs);
59     FILE_INODE(filp) = tip;
60     tip->i_flags |= MS_NOATIME; /* Disable updating access times. */
61     filp->f_flags = O_RDWR;
62 #if defined(AFS_LINUX24_ENV)
63     filp->f_mode = FMODE_READ|FMODE_WRITE;
64     filp->f_op = fops_get(tip->i_fop);
65 #else
66     filp->f_op = tip->i_op->default_file_ops;
67 #endif
68     if (filp->f_op && filp->f_op->open)
69         code = filp->f_op->open(tip, filp);
70     if (code)
71         osi_Panic("Can't open inode %d\n", ainode->ufs);
72     afile->size = i_size_read(tip);
73     AFS_GLOCK();
74     afile->offset = 0;
75     afile->proc = (int (*)())0;
76     return (void *)afile;
77 }
78
79 void osi_get_fh(struct dentry *dp, afs_ufs_dcache_id_t *ainode) {
80     *ainode = dp->d_inode->i_ino;
81 }
82
83 int
84 afs_osi_Stat(struct osi_file *afile, struct osi_stat *astat)
85 {
86     afs_int32 code;
87     AFS_STATCNT(osi_Stat);
88     ObtainWriteLock(&afs_xosi, 320);
89     astat->size = i_size_read(OSIFILE_INODE(afile));
90     astat->mtime = OSIFILE_INODE(afile)->i_mtime;
91     astat->atime = OSIFILE_INODE(afile)->i_atime;
92     code = 0;
93     ReleaseWriteLock(&afs_xosi);
94     return code;
95 }
96
97 int
98 osi_UFSClose(struct osi_file *afile)
99 {
100     AFS_STATCNT(osi_Close);
101     if (afile) {
102         if (FILE_INODE(&afile->file)) {
103             struct file *filp = &afile->file;
104             if (filp->f_op && filp->f_op->release)
105                 filp->f_op->release(FILE_INODE(filp), filp);
106             iput(FILE_INODE(filp));
107         }
108     }
109
110     osi_FreeLargeSpace(afile);
111     return 0;
112 }
113
114 int
115 osi_UFSTruncate(struct osi_file *afile, afs_int32 asize)
116 {
117     afs_int32 code;
118     struct osi_stat tstat;
119     struct iattr newattrs;
120     struct inode *inode = OSIFILE_INODE(afile);
121     AFS_STATCNT(osi_Truncate);
122
123     /* This routine only shrinks files, and most systems
124      * have very slow truncates, even when the file is already
125      * small enough.  Check now and save some time.
126      */
127     code = afs_osi_Stat(afile, &tstat);
128     if (code || tstat.size <= asize)
129         return code;
130     ObtainWriteLock(&afs_xosi, 321);
131     AFS_GUNLOCK();
132 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
133     down_write(&inode->i_alloc_sem);
134 #endif
135 #ifdef STRUCT_INODE_HAS_I_MUTEX
136     mutex_lock(&inode->i_mutex);
137 #else
138     down(&inode->i_sem);
139 #endif
140     newattrs.ia_size = asize;
141     newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
142 #if defined(AFS_LINUX24_ENV)
143     newattrs.ia_ctime = CURRENT_TIME;
144
145     /* avoid notify_change() since it wants to update dentry->d_parent */
146     lock_kernel();
147     code = inode_change_ok(inode, &newattrs);
148     if (!code) {
149 #ifdef INODE_SETATTR_NOT_VOID
150         code = inode_setattr(inode, &newattrs);
151 #else
152         inode_setattr(inode, &newattrs);
153 #endif
154     }
155     unlock_kernel();
156     if (!code)
157         truncate_inode_pages(&inode->i_data, asize);
158 #else
159     i_size_write(inode, asize);
160     if (inode->i_sb->s_op && inode->i_sb->s_op->notify_change) {
161         code = inode->i_sb->s_op->notify_change(&afile->dentry, &newattrs);
162     }
163     if (!code) {
164         truncate_inode_pages(inode, asize);
165         if (inode->i_op && inode->i_op->truncate)
166             inode->i_op->truncate(inode);
167     }
168 #endif
169     code = -code;
170 #ifdef STRUCT_INODE_HAS_I_MUTEX
171     mutex_unlock(&inode->i_mutex);
172 #else
173     up(&inode->i_sem);
174 #endif
175 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
176     up_write(&inode->i_alloc_sem);
177 #endif
178     AFS_GLOCK();
179     ReleaseWriteLock(&afs_xosi);
180     return code;
181 }
182
183
184 /* Generic read interface */
185 int
186 afs_osi_Read(struct osi_file *afile, int offset, void *aptr,
187              afs_int32 asize)
188 {
189     struct uio auio;
190     struct iovec iov;
191     afs_int32 code;
192
193     AFS_STATCNT(osi_Read);
194
195     /*
196      * If the osi_file passed in is NULL, panic only if AFS is not shutting
197      * down. No point in crashing when we are already shutting down
198      */
199     if (!afile) {
200         if (!afs_shuttingdown)
201             osi_Panic("osi_Read called with null param");
202         else
203             return -EIO;
204     }
205
206     if (offset != -1)
207         afile->offset = offset;
208     setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_READ, AFS_UIOSYS);
209     AFS_GUNLOCK();
210     code = osi_rdwr(afile, &auio, UIO_READ);
211     AFS_GLOCK();
212     if (code == 0) {
213         code = asize - auio.uio_resid;
214         afile->offset += code;
215     } else {
216         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, auio.uio_resid,
217                    ICL_TYPE_INT32, code);
218         if (code > 0) {
219             code *= -1;
220         }
221     }
222     return code;
223 }
224
225 /* Generic write interface */
226 int
227 afs_osi_Write(struct osi_file *afile, afs_int32 offset, void *aptr,
228               afs_int32 asize)
229 {
230     struct uio auio;
231     struct iovec iov;
232     afs_int32 code;
233
234     AFS_STATCNT(osi_Write);
235
236     if (!afile) {
237         if (!afs_shuttingdown)
238             osi_Panic("afs_osi_Write called with null param");
239         else
240             return -EIO;
241     }
242
243     if (offset != -1)
244         afile->offset = offset;
245     setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_WRITE, AFS_UIOSYS);
246     AFS_GUNLOCK();
247     code = osi_rdwr(afile, &auio, UIO_WRITE);
248     AFS_GLOCK();
249     if (code == 0) {
250         code = asize - auio.uio_resid;
251         afile->offset += code;
252     } else {
253         if (code == ENOSPC)
254             afs_warnuser
255                 ("\n\n\n*** Cache partition is FULL - Decrease cachesize!!! ***\n\n");
256         if (code > 0) {
257             code *= -1;
258         }
259     }
260
261     if (afile->proc)
262         (*afile->proc)(afile, code);
263
264     return code;
265 }
266
267
268 /*  This work should be handled by physstrat in ca/machdep.c.
269     This routine written from the RT NFS port strategy routine.
270     It has been generalized a bit, but should still be pretty clear. */
271 int
272 afs_osi_MapStrategy(int (*aproc) (struct buf * bp), struct buf *bp)
273 {
274     afs_int32 returnCode;
275
276     AFS_STATCNT(osi_MapStrategy);
277     returnCode = (*aproc) (bp);
278
279     return returnCode;
280 }
281
282 void
283 shutdown_osifile(void)
284 {
285     AFS_STATCNT(shutdown_osifile);
286     if (afs_cold_shutdown) {
287         afs_osicred_initialized = 0;
288     }
289 }
290
291 /* Intialize cache device info and fragment size for disk cache partition. */
292 int
293 osi_InitCacheInfo(char *aname)
294 {
295     int code;
296     extern afs_dcache_id_t cacheInode;
297     struct dentry *dp;
298     extern struct osi_dev cacheDev;
299     extern afs_int32 afs_fsfragsize;
300     extern struct super_block *afs_cacheSBp;
301     extern struct vfsmount *afs_cacheMnt;
302     code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp);
303     if (code)
304         return ENOENT;
305
306     osi_get_fh(dp, &cacheInode.ufs);
307     cacheDev.dev = dp->d_inode->i_sb->s_dev;
308     afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
309     afs_cacheSBp = dp->d_inode->i_sb;
310
311     dput(dp);
312
313     return 0;
314 }
315
316
317 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
318 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
319
320 /* osi_rdwr
321  * seek, then read or write to an open inode. addrp points to data in
322  * kernel space.
323  */
324 int
325 osi_rdwr(struct osi_file *osifile, struct uio *uiop, int rw)
326 {
327     struct file *filp = &osifile->file;
328     KERNEL_SPACE_DECL;
329     int code = 0;
330     struct iovec *iov;
331     afs_size_t count;
332     unsigned long savelim;
333
334     savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
335     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
336
337     if (uiop->uio_seg == AFS_UIOSYS)
338         TO_USER_SPACE();
339
340     /* seek to the desired position. Return -1 on error. */
341     if (filp->f_op->llseek) {
342         if (filp->f_op->llseek(filp, (loff_t) uiop->uio_offset, 0) != uiop->uio_offset)
343             return -1;
344     } else
345         filp->f_pos = uiop->uio_offset;
346
347     while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
348         iov = uiop->uio_iov;
349         count = iov->iov_len;
350         if (count == 0) {
351             uiop->uio_iov++;
352             uiop->uio_iovcnt--;
353             continue;
354         }
355
356         if (rw == UIO_READ)
357             code = FOP_READ(filp, iov->iov_base, count);
358         else
359             code = FOP_WRITE(filp, iov->iov_base, count);
360
361         if (code < 0) {
362             code = -code;
363             break;
364         } else if (code == 0) {
365             /*
366              * This is bad -- we can't read any more data from the
367              * file, but we have no good way of signaling a partial
368              * read either.
369              */
370             code = EIO;
371             break;
372         }
373
374         iov->iov_base += code;
375         iov->iov_len -= code;
376         uiop->uio_resid -= code;
377         uiop->uio_offset += code;
378         code = 0;
379     }
380
381     if (uiop->uio_seg == AFS_UIOSYS)
382         TO_KERNEL_SPACE();
383
384     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
385
386     return code;
387 }
388
389 /* setup_uio 
390  * Setup a uio struct.
391  */
392 void
393 setup_uio(struct uio *uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos,
394           int count, uio_flag_t flag, uio_seg_t seg)
395 {
396     iovecp->iov_base = (char *)buf;
397     iovecp->iov_len = count;
398     uiop->uio_iov = iovecp;
399     uiop->uio_iovcnt = 1;
400     uiop->uio_offset = pos;
401     uiop->uio_seg = seg;
402     uiop->uio_resid = count;
403     uiop->uio_flag = flag;
404 }
405
406
407 /* uiomove
408  * UIO_READ : dp -> uio
409  * UIO_WRITE : uio -> dp
410  */
411 int
412 uiomove(char *dp, int length, uio_flag_t rw, struct uio *uiop)
413 {
414     int count;
415     struct iovec *iov;
416     int code;
417
418     while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
419         iov = uiop->uio_iov;
420         count = iov->iov_len;
421
422         if (!count) {
423             uiop->uio_iov++;
424             uiop->uio_iovcnt--;
425             continue;
426         }
427
428         if (count > length)
429             count = length;
430
431         switch (uiop->uio_seg) {
432         case AFS_UIOSYS:
433             switch (rw) {
434             case UIO_READ:
435                 memcpy(iov->iov_base, dp, count);
436                 break;
437             case UIO_WRITE:
438                 memcpy(dp, iov->iov_base, count);
439                 break;
440             default:
441                 printf("uiomove: Bad rw = %d\n", rw);
442                 return -EINVAL;
443             }
444             break;
445         case AFS_UIOUSER:
446             switch (rw) {
447             case UIO_READ:
448                 AFS_COPYOUT(dp, iov->iov_base, count, code);
449                 break;
450             case UIO_WRITE:
451                 AFS_COPYIN(iov->iov_base, dp, count, code);
452                 break;
453             default:
454                 printf("uiomove: Bad rw = %d\n", rw);
455                 return -EINVAL;
456             }
457             break;
458         default:
459             printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
460             return -EINVAL;
461         }
462
463         dp += count;
464         length -= count;
465         iov->iov_base += count;
466         iov->iov_len -= count;
467         uiop->uio_offset += count;
468         uiop->uio_resid -= count;
469     }
470     return 0;
471 }
472