Ukernel prototypes
[openafs.git] / src / afs / VNOPS / afs_vnop_open.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_open
13  *
14  */
15
16
17 #include <afsconfig.h>
18 #include "afs/param.h"
19
20
21 #include "afs/sysincludes.h"    /* Standard vendor system headers */
22 #include "afsincludes.h"        /* Afs-based standard headers */
23 #include "afs/afs_stats.h"      /* statistics */
24 #include "afs/afs_cbqueue.h"
25 #include "afs/nfsclient.h"
26 #include "afs/afs_osidnlc.h"
27
28
29
30 /* given a vnode ptr, open flags and credentials, open the file.  No access
31  * checks are done here, instead they're done by afs_create or afs_access,
32  * both called by the vn_open call.
33  */
34 int
35 #ifdef AFS_SGI64_ENV
36 afs_open(bhv_desc_t * bhv, struct vcache **avcp, afs_int32 aflags,
37          struct AFS_UCRED *acred)
38 #else
39 afs_open(struct vcache **avcp, afs_int32 aflags, struct AFS_UCRED *acred)
40 #endif
41 {
42     register afs_int32 code;
43     struct vrequest treq;
44     struct vcache *tvc;
45     int writing;
46     struct afs_fakestat_state fakestate;
47
48     AFS_STATCNT(afs_open);
49     if ((code = afs_InitReq(&treq, acred)))
50         return code;
51 #ifdef AFS_SGI64_ENV
52     /* avcpp can be, but is not necesarily, bhp's vnode. */
53     tvc = VTOAFS(BHV_TO_VNODE(bhv));
54 #else
55     tvc = *avcp;
56 #endif
57     afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc,
58                ICL_TYPE_INT32, aflags);
59     afs_InitFakeStat(&fakestate);
60
61     AFS_DISCON_LOCK();
62
63     code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
64     if (code)
65         goto done;
66     code = afs_VerifyVCache(tvc, &treq);
67     if (code)
68         goto done;
69
70     ObtainReadLock(&tvc->lock);
71
72 #ifdef AFS_DISCON_ENV
73     if (AFS_IS_DISCONNECTED && (afs_DCacheMissingChunks(tvc) != 0)) {
74        ReleaseReadLock(&tvc->lock);
75        printf("Network is down in afs_open: missing chunks\n");
76        code = ENETDOWN;
77        goto done;
78     }
79 #endif
80
81     ReleaseReadLock(&tvc->lock);
82
83     if (aflags & (FWRITE | FTRUNC))
84         writing = 1;
85     else
86         writing = 0;
87     if (vType(tvc) == VDIR) {
88         /* directory */
89         if (writing) {
90             code = EISDIR;
91             goto done;
92         } else {
93             if (!afs_AccessOK
94                 (tvc, ((tvc->f.states & CForeign) ? PRSFS_READ : PRSFS_LOOKUP),
95                  &treq, CHECK_MODE_BITS)) {
96                 code = EACCES;
97                 printf("afs_Open: no access for dir\n");
98                 goto done;
99             }
100         }
101     } else {
102 #ifdef  AFS_SUN5_ENV
103         if (AFS_NFSXLATORREQ(acred) && (aflags & FREAD)) {
104             if (!afs_AccessOK
105                 (tvc, PRSFS_READ, &treq,
106                  CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
107                 code = EACCES;
108                 goto done;
109             }
110         }
111 #endif
112 #ifdef  AFS_AIX41_ENV
113         if (aflags & FRSHARE) {
114             /*
115              * Hack for AIX 4.1:
116              *  Apparently it is possible for a file to get mapped without
117              *  either VNOP_MAP or VNOP_RDWR being called, if (1) it is a
118              *  sharable library, and (2) it has already been loaded.  We must
119              *  ensure that the credp is up to date.  We detect the situation
120              *  by checking for O_RSHARE at open time.
121              */
122             /*
123              * We keep the caller's credentials since an async daemon will
124              * handle the request at some point. We assume that the same
125              * credentials will be used.
126              */
127             ObtainWriteLock(&tvc->lock, 140);
128             if (!tvc->credp || (tvc->credp != acred)) {
129                 crhold(acred);
130                 if (tvc->credp) {
131                     struct ucred *crp = tvc->credp;
132                     tvc->credp = NULL;
133                     crfree(crp);
134                 }
135                 tvc->credp = acred;
136             }
137             ReleaseWriteLock(&tvc->lock);
138         }
139 #endif
140         /* normal file or symlink */
141         osi_FlushText(tvc);     /* only needed to flush text if text locked last time */
142 #ifdef AFS_BOZONLOCK_ENV
143         afs_BozonLock(&tvc->pvnLock, tvc);
144 #endif
145         osi_FlushPages(tvc, acred);
146 #ifdef AFS_BOZONLOCK_ENV
147         afs_BozonUnlock(&tvc->pvnLock, tvc);
148 #endif
149     }
150     /* set date on file if open in O_TRUNC mode */
151     if (aflags & FTRUNC) {
152         /* this fixes touch */
153         ObtainWriteLock(&tvc->lock, 123);
154         tvc->f.m.Date = osi_Time();
155         tvc->f.states |= CDirty;
156         ReleaseWriteLock(&tvc->lock);
157     }
158     ObtainReadLock(&tvc->lock);
159     if (writing)
160         tvc->execsOrWriters++;
161     tvc->opens++;
162 #if defined(AFS_SGI_ENV)
163     if (writing && tvc->cred == NULL) {
164         crhold(acred);
165         tvc->cred = acred;
166     }
167 #endif
168     ReleaseReadLock(&tvc->lock);
169     if ((afs_preCache != 0) && (writing == 0) && (vType(tvc) != VDIR) && 
170         (!afs_BBusy())) {
171         register struct dcache *tdc;
172         afs_size_t offset, len;
173
174         tdc = afs_GetDCache(tvc, 0, &treq, &offset, &len, 1);
175
176         ObtainSharedLock(&tdc->mflock, 865);
177         if (!(tdc->mflags & DFFetchReq)) {
178             struct brequest *bp;
179
180             /* start the daemon (may already be running, however) */
181             UpgradeSToWLock(&tdc->mflock, 666);
182             tdc->mflags |= DFFetchReq;  /* guaranteed to be cleared by BKG or 
183                                            GetDCache */
184             /* last parm (1) tells bkg daemon to do an afs_PutDCache when it 
185                is done, since we don't want to wait for it to finish before 
186                doing so ourselves.
187             */
188             bp = afs_BQueue(BOP_FETCH, tvc, B_DONTWAIT, 0, acred,
189                             (afs_size_t) 0, (afs_size_t) 1, tdc);
190             if (!bp) {
191                 tdc->mflags &= ~DFFetchReq;
192             }
193             ReleaseWriteLock(&tdc->mflock);
194         } else {
195             ReleaseSharedLock(&tdc->mflock);
196         }
197     }   
198   done:
199     afs_PutFakeStat(&fakestate);
200     AFS_DISCON_UNLOCK();
201
202     code = afs_CheckCode(code, &treq, 4);       /* avoid AIX -O bug */
203
204     afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc,
205                ICL_TYPE_INT32, 999999);
206
207     return code;
208 }