98f931edc3460309a37a83e0fd9aeca73087488b
[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         code = -1;
219     }
220     return code;
221 }
222
223 /* Generic write interface */
224 int
225 afs_osi_Write(struct osi_file *afile, afs_int32 offset, void *aptr,
226               afs_int32 asize)
227 {
228     struct uio auio;
229     struct iovec iov;
230     afs_int32 code;
231
232     AFS_STATCNT(osi_Write);
233
234     if (!afile) {
235         if (!afs_shuttingdown)
236             osi_Panic("afs_osi_Write called with null param");
237         else
238             return EIO;
239     }
240
241     if (offset != -1)
242         afile->offset = offset;
243     setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_WRITE, AFS_UIOSYS);
244     AFS_GUNLOCK();
245     code = osi_rdwr(afile, &auio, UIO_WRITE);
246     AFS_GLOCK();
247     if (code == 0) {
248         code = asize - auio.uio_resid;
249         afile->offset += code;
250     } else {
251         if (code == ENOSPC)
252             afs_warnuser
253                 ("\n\n\n*** Cache partition is FULL - Decrease cachesize!!! ***\n\n");
254         code = -1;
255     }
256
257     if (afile->proc)
258         (*afile->proc)(afile, code);
259
260     return code;
261 }
262
263
264 /*  This work should be handled by physstrat in ca/machdep.c.
265     This routine written from the RT NFS port strategy routine.
266     It has been generalized a bit, but should still be pretty clear. */
267 int
268 afs_osi_MapStrategy(int (*aproc) (struct buf * bp), struct buf *bp)
269 {
270     afs_int32 returnCode;
271
272     AFS_STATCNT(osi_MapStrategy);
273     returnCode = (*aproc) (bp);
274
275     return returnCode;
276 }
277
278 void
279 shutdown_osifile(void)
280 {
281     AFS_STATCNT(shutdown_osifile);
282     if (afs_cold_shutdown) {
283         afs_osicred_initialized = 0;
284     }
285 }
286
287 /* Intialize cache device info and fragment size for disk cache partition. */
288 int
289 osi_InitCacheInfo(char *aname)
290 {
291     int code;
292     extern afs_dcache_id_t cacheInode;
293     struct dentry *dp;
294     extern struct osi_dev cacheDev;
295     extern afs_int32 afs_fsfragsize;
296     extern struct super_block *afs_cacheSBp;
297     extern struct vfsmount *afs_cacheMnt;
298     code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp);
299     if (code)
300         return ENOENT;
301
302     osi_get_fh(dp, &cacheInode.ufs);
303     cacheDev.dev = dp->d_inode->i_sb->s_dev;
304     afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
305     afs_cacheSBp = dp->d_inode->i_sb;
306
307     dput(dp);
308
309     return 0;
310 }
311
312
313 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
314 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
315
316 /* osi_rdwr
317  * seek, then read or write to an open inode. addrp points to data in
318  * kernel space.
319  */
320 int
321 osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
322 {
323     struct file *filp = &osifile->file;
324     KERNEL_SPACE_DECL;
325     int code = 0;
326     struct iovec *iov;
327     afs_size_t count;
328     unsigned long savelim;
329
330     savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
331     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
332
333     if (uiop->uio_seg == AFS_UIOSYS)
334         TO_USER_SPACE();
335
336     /* seek to the desired position. Return -1 on error. */
337     if (filp->f_op->llseek) {
338         if (filp->f_op->llseek(filp, (loff_t) uiop->uio_offset, 0) != uiop->uio_offset)
339             return -1;
340     } else
341         filp->f_pos = uiop->uio_offset;
342
343     while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
344         iov = uiop->uio_iov;
345         count = iov->iov_len;
346         if (count == 0) {
347             uiop->uio_iov++;
348             uiop->uio_iovcnt--;
349             continue;
350         }
351
352         if (rw == UIO_READ)
353             code = FOP_READ(filp, iov->iov_base, count);
354         else
355             code = FOP_WRITE(filp, iov->iov_base, count);
356
357         if (code < 0) {
358             code = -code;
359             break;
360         } else if (code == 0) {
361             /*
362              * This is bad -- we can't read any more data from the
363              * file, but we have no good way of signaling a partial
364              * read either.
365              */
366             code = EIO;
367             break;
368         }
369
370         iov->iov_base += code;
371         iov->iov_len -= code;
372         uiop->uio_resid -= code;
373         uiop->uio_offset += code;
374         code = 0;
375     }
376
377     if (uiop->uio_seg == AFS_UIOSYS)
378         TO_KERNEL_SPACE();
379
380     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
381
382     return code;
383 }
384
385 /* setup_uio 
386  * Setup a uio struct.
387  */
388 void
389 setup_uio(uio_t * uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos,
390           int count, uio_flag_t flag, uio_seg_t seg)
391 {
392     iovecp->iov_base = (char *)buf;
393     iovecp->iov_len = count;
394     uiop->uio_iov = iovecp;
395     uiop->uio_iovcnt = 1;
396     uiop->uio_offset = pos;
397     uiop->uio_seg = seg;
398     uiop->uio_resid = count;
399     uiop->uio_flag = flag;
400 }
401
402
403 /* uiomove
404  * UIO_READ : dp -> uio
405  * UIO_WRITE : uio -> dp
406  */
407 int
408 uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
409 {
410     int count;
411     struct iovec *iov;
412     int code;
413
414     while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
415         iov = uiop->uio_iov;
416         count = iov->iov_len;
417
418         if (!count) {
419             uiop->uio_iov++;
420             uiop->uio_iovcnt--;
421             continue;
422         }
423
424         if (count > length)
425             count = length;
426
427         switch (uiop->uio_seg) {
428         case AFS_UIOSYS:
429             switch (rw) {
430             case UIO_READ:
431                 memcpy(iov->iov_base, dp, count);
432                 break;
433             case UIO_WRITE:
434                 memcpy(dp, iov->iov_base, count);
435                 break;
436             default:
437                 printf("uiomove: Bad rw = %d\n", rw);
438                 return -EINVAL;
439             }
440             break;
441         case AFS_UIOUSER:
442             switch (rw) {
443             case UIO_READ:
444                 AFS_COPYOUT(dp, iov->iov_base, count, code);
445                 break;
446             case UIO_WRITE:
447                 AFS_COPYIN(iov->iov_base, dp, count, code);
448                 break;
449             default:
450                 printf("uiomove: Bad rw = %d\n", rw);
451                 return -EINVAL;
452             }
453             break;
454         default:
455             printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
456             return -EINVAL;
457         }
458
459         dp += count;
460         length -= count;
461         iov->iov_base += count;
462         iov->iov_len -= count;
463         uiop->uio_offset += count;
464         uiop->uio_resid -= count;
465     }
466     return 0;
467 }
468