initial-freebsd-port-work-20010414
[openafs.git] / src / afs / VNOPS / afs_vnop_strategy.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  * Implements:
12  * afs_ustrategy
13  */
14
15 #include "../afs/param.h"       /* Should be always first */
16 #if !defined(AFS_HPUX_ENV) && !defined(AFS_SGI_ENV) && !defined(AFS_LINUX20_ENV)
17
18 #include "../afs/sysincludes.h" /* Standard vendor system headers */
19 #include "../afs/afsincludes.h" /* Afs-based standard headers */
20 #include "../afs/afs_stats.h" /* statistics */
21 #include "../afs/afs_cbqueue.h"
22 #include "../afs/nfsclient.h"
23 #include "../afs/afs_osidnlc.h"
24
25
26
27
28 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
29 afs_ustrategy(abp, credp)
30     struct AFS_UCRED *credp;
31 #else
32 afs_ustrategy(abp)
33 #endif
34     register struct buf *abp; {
35     register afs_int32 code;
36     struct uio tuio;
37     register struct vcache *tvc = (struct vcache *) abp->b_vp;
38     register afs_int32 len = abp->b_bcount;
39 #if     !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
40 #ifdef  AFS_AIX41_ENV
41     struct ucred *credp;
42 #else
43     struct AFS_UCRED *credp = u.u_cred;
44 #endif
45 #endif
46 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
47     int async = abp->b_flags & B_ASYNC;
48 #endif
49     struct iovec tiovec[1];
50
51     AFS_STATCNT(afs_ustrategy);
52 #ifdef  AFS_AIX41_ENV
53     /*
54      * So that it won't change while reading it
55      */
56     ObtainReadLock(&tvc->lock);
57     if (tvc->credp) {   
58         credp = tvc->credp;
59         crhold(credp);
60     } else {
61         credp = crref();
62     }
63     ReleaseReadLock(&tvc->lock);
64     osi_Assert(credp);
65 #endif
66     if ((abp->b_flags & B_READ) == B_READ) {
67         /* read b_bcount bytes into kernel address b_un.b_addr starting
68             at byte DEV_BSIZE * b_blkno.  Bzero anything we can't read,
69             and finally call iodone(abp).  File is in abp->b_vp.  Credentials
70             are from u area??
71         */
72         tuio.afsio_iov = tiovec;
73         tuio.afsio_iovcnt = 1;
74 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_FBSD_ENV)
75         tuio.afsio_offset = (u_int) dbtob(abp->b_blkno);
76 #if     defined(AFS_SUN5_ENV)
77         tuio._uio_offset._p._u = 0;
78 #endif
79 #else
80         tuio.afsio_offset = DEV_BSIZE * abp->b_blkno;
81 #endif
82         tuio.afsio_seg = AFS_UIOSYS;
83 #ifdef AFS_UIOFMODE
84         tuio.afsio_fmode = 0;
85 #endif
86         tuio.afsio_resid = abp->b_bcount;
87 #if defined(AFS_FBSD_ENV)
88         tiovec[0].iov_base = abp->b_saveaddr;
89 #else
90         tiovec[0].iov_base = abp->b_un.b_addr;
91 #endif /* AFS_FBSD_ENV */
92         tiovec[0].iov_len = abp->b_bcount;
93         /* are user's credentials valid here?  probably, but this
94              sure seems like the wrong things to do. */
95 #if     defined(AFS_SUN5_ENV)
96         code = afs_nlrdwr((struct vcache *) abp->b_vp, &tuio, UIO_READ, 0, credp);
97 #else
98         code = afs_rdwr((struct vcache *) abp->b_vp, &tuio, UIO_READ, 0, credp);
99 #endif
100         if (code == 0) {
101             if (tuio.afsio_resid > 0)
102 #if defined(AFS_FBSD_ENV)
103                 bzero(abp->b_saveaddr + abp->b_bcount - tuio.afsio_resid, tuio.afsio_resid);
104 #else
105                 bzero(abp->b_un.b_addr + abp->b_bcount - tuio.afsio_resid, tuio.afsio_resid);
106 #endif /* AFS_FBSD_ENV */
107 #ifdef  AFS_AIX32_ENV
108             /*
109              * If we read a block that is past EOF and the user was not storing
110              * to it, go ahead and write protect the page. This way we will detect
111              * storing beyond EOF in the future
112              */
113             if (dbtob(abp->b_blkno) + abp->b_bcount > tvc->m.Length) {
114                 if ((abp->b_flags & B_PFSTORE) == 0) {
115                     AFS_GUNLOCK();
116                     vm_protectp(tvc->vmh, dbtob(abp->b_blkno)/PAGESIZE,
117                                 abp->b_bcount/PAGESIZE, RDONLY);
118                     AFS_GLOCK();
119                 }
120             }
121 #endif
122         }
123     }
124     else {
125         tuio.afsio_iov = tiovec;
126         tuio.afsio_iovcnt = 1;
127 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
128         tuio.afsio_offset = (u_int) dbtob(abp->b_blkno);
129 #ifdef  AFS_SUN5_ENV
130         tuio._uio_offset._p._u = 0;
131         tuio.uio_limit = u.u_rlimit[RLIMIT_FSIZE].rlim_cur;
132 #endif
133 #else
134         tuio.afsio_offset = DEV_BSIZE * abp->b_blkno;
135 #endif
136         tuio.afsio_seg = AFS_UIOSYS;
137 #ifdef AFS_UIOFMODE
138         tuio.afsio_fmode = 0;
139 #endif
140 #ifdef  AFS_AIX32_ENV   
141         /*
142          * XXX It this really right? Ideally we should always write block size multiple
143          * and not any arbitrary size, right? XXX
144          */
145         len = MIN(len, tvc->m.Length - dbtob(abp->b_blkno));
146 #endif
147 #ifdef  AFS_ALPHA_ENV
148         len = MIN(abp->b_bcount, ((struct vcache *)abp->b_vp)->m.Length - dbtob(abp->b_blkno));
149 #endif  /* AFS_ALPHA_ENV */
150         tuio.afsio_resid = len;
151 #if defined(AFS_FBSD_ENV)
152         tiovec[0].iov_base = abp->b_saveaddr;
153 #else
154         tiovec[0].iov_base = abp->b_un.b_addr;
155 #endif /* AFS_FBSD_ENV */
156         tiovec[0].iov_len = len;
157         /* are user's credentials valid here?  probably, but this
158              sure seems like the wrong things to do. */
159 #if     defined(AFS_SUN5_ENV)
160         code = afs_nlrdwr((struct vcache *) abp->b_vp, &tuio, UIO_WRITE, 0, credp);
161 #else
162         code = afs_rdwr((struct vcache *) abp->b_vp, &tuio, UIO_WRITE, 0, credp);
163 #endif
164     }
165 #if     !defined(AFS_AIX32_ENV) && !defined(AFS_SUN5_ENV)
166 #ifdef AFS_DUX40_ENV
167     if (code) {
168         abp->b_error = code;
169         abp->b_flags |= B_ERROR;
170     }
171     biodone(abp);
172     if (code && !(abp->b_flags & B_READ)) {
173         /* prevent ubc from retrying writes */
174         AFS_GUNLOCK();
175         ubc_invalidate(((struct vnode *)tvc)->v_object,
176                        (vm_offset_t)dbtob(abp->b_blkno),
177                        PAGE_SIZE, B_INVAL);
178         AFS_GLOCK();
179     }
180 #else  /* AFS_DUX40_ENV */
181     iodone(abp);
182 #endif /* AFS_DUX40_ENV */
183 #endif
184 #ifdef  AFS_AIX32_ENV
185     crfree(credp);
186 #endif
187     afs_Trace3(afs_iclSetp, CM_TRACE_STRATEGYDONE, ICL_TYPE_POINTER, tvc,
188                ICL_TYPE_INT32, code,
189                ICL_TYPE_LONG, tuio.afsio_resid);
190     return code;
191 }
192
193 #endif /* !AFS_HPUX_ENV  && !AFS_SGI_ENV && !AFS_LINUX20_ENV */