Commit | Line | Data |
---|---|---|
805e021f CE |
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 | afs_ucred_t *acred) | |
38 | #else | |
39 | afs_open(struct vcache **avcp, afs_int32 aflags, afs_ucred_t *acred) | |
40 | #endif | |
41 | { | |
42 | afs_int32 code; | |
43 | struct vrequest *treq = NULL; | |
44 | struct vcache *tvc; | |
45 | int writing; | |
46 | struct afs_fakestat_state fakestate; | |
47 | ||
48 | AFS_STATCNT(afs_open); | |
49 | if ((code = afs_CreateReq(&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 | if (AFS_IS_DISCONNECTED && (afs_DCacheMissingChunks(tvc) != 0)) { | |
73 | ReleaseReadLock(&tvc->lock); | |
74 | /* printf("Network is down in afs_open: missing chunks\n"); */ | |
75 | code = ENETDOWN; | |
76 | goto done; | |
77 | } | |
78 | ||
79 | ReleaseReadLock(&tvc->lock); | |
80 | ||
81 | if (aflags & (FWRITE | FTRUNC)) | |
82 | writing = 1; | |
83 | else | |
84 | writing = 0; | |
85 | if (vType(tvc) == VDIR) { | |
86 | /* directory */ | |
87 | if (writing) { | |
88 | code = EISDIR; | |
89 | goto done; | |
90 | } else { | |
91 | if (!afs_AccessOK | |
92 | (tvc, ((tvc->f.states & CForeign) ? PRSFS_READ : PRSFS_LOOKUP), | |
93 | treq, CHECK_MODE_BITS)) { | |
94 | code = EACCES; | |
95 | /* printf("afs_Open: no access for dir\n"); */ | |
96 | goto done; | |
97 | } | |
98 | } | |
99 | } else { | |
100 | #ifdef AFS_SUN5_ENV | |
101 | if (AFS_NFSXLATORREQ(acred) && (aflags & FREAD)) { | |
102 | if (!afs_AccessOK | |
103 | (tvc, PRSFS_READ, treq, | |
104 | CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) { | |
105 | code = EACCES; | |
106 | goto done; | |
107 | } | |
108 | } | |
109 | #endif | |
110 | #ifdef AFS_AIX41_ENV | |
111 | if (aflags & FRSHARE) { | |
112 | /* | |
113 | * Hack for AIX 4.1: | |
114 | * Apparently it is possible for a file to get mapped without | |
115 | * either VNOP_MAP or VNOP_RDWR being called, if (1) it is a | |
116 | * sharable library, and (2) it has already been loaded. We must | |
117 | * ensure that the credp is up to date. We detect the situation | |
118 | * by checking for O_RSHARE at open time. | |
119 | */ | |
120 | /* | |
121 | * We keep the caller's credentials since an async daemon will | |
122 | * handle the request at some point. We assume that the same | |
123 | * credentials will be used. | |
124 | */ | |
125 | ObtainWriteLock(&tvc->lock, 140); | |
126 | if (!tvc->credp || (tvc->credp != acred)) { | |
127 | crhold(acred); | |
128 | if (tvc->credp) { | |
129 | struct ucred *crp = tvc->credp; | |
130 | tvc->credp = NULL; | |
131 | crfree(crp); | |
132 | } | |
133 | tvc->credp = acred; | |
134 | } | |
135 | ReleaseWriteLock(&tvc->lock); | |
136 | } | |
137 | #endif | |
138 | /* normal file or symlink */ | |
139 | osi_FlushText(tvc); /* only needed to flush text if text locked last time */ | |
140 | osi_FlushPages(tvc, acred); | |
141 | } | |
142 | /* set date on file if open in O_TRUNC mode */ | |
143 | if (aflags & FTRUNC) { | |
144 | /* this fixes touch */ | |
145 | ObtainWriteLock(&tvc->lock, 123); | |
146 | tvc->f.m.Date = osi_Time(); | |
147 | tvc->f.states |= CDirty; | |
148 | ReleaseWriteLock(&tvc->lock); | |
149 | } | |
150 | ObtainReadLock(&tvc->lock); | |
151 | if (writing) | |
152 | tvc->execsOrWriters++; | |
153 | tvc->opens++; | |
154 | #if defined(AFS_SGI_ENV) || defined (AFS_LINUX26_ENV) | |
155 | if (writing && tvc->cred == NULL) { | |
156 | crhold(acred); | |
157 | tvc->cred = acred; | |
158 | } | |
159 | #endif | |
160 | ReleaseReadLock(&tvc->lock); | |
161 | if ((afs_preCache != 0) && (writing == 0) && (vType(tvc) != VDIR) && | |
162 | (!afs_BBusy())) { | |
163 | struct dcache *tdc; | |
164 | afs_size_t offset, len; | |
165 | ||
166 | tdc = afs_GetDCache(tvc, 0, treq, &offset, &len, 1); | |
167 | if (tdc) { | |
168 | ObtainSharedLock(&tdc->mflock, 865); | |
169 | if (!(tdc->mflags & DFFetchReq)) { | |
170 | struct brequest *bp; | |
171 | ||
172 | /* start the daemon (may already be running, however) */ | |
173 | UpgradeSToWLock(&tdc->mflock, 666); | |
174 | tdc->mflags |= DFFetchReq; /* guaranteed to be cleared by BKG or | |
175 | GetDCache */ | |
176 | /* last parm (1) tells bkg daemon to do an afs_PutDCache when it | |
177 | is done, since we don't want to wait for it to finish before | |
178 | doing so ourselves. | |
179 | */ | |
180 | bp = afs_BQueue(BOP_FETCH, tvc, B_DONTWAIT, 0, acred, | |
181 | (afs_size_t) 0, (afs_size_t) 1, tdc, | |
182 | (void *)0, (void *)0); | |
183 | if (!bp) { | |
184 | tdc->mflags &= ~DFFetchReq; | |
185 | } | |
186 | ReleaseWriteLock(&tdc->mflock); | |
187 | } else { | |
188 | ReleaseSharedLock(&tdc->mflock); | |
189 | } | |
190 | } | |
191 | } | |
192 | done: | |
193 | afs_PutFakeStat(&fakestate); | |
194 | AFS_DISCON_UNLOCK(); | |
195 | ||
196 | code = afs_CheckCode(code, treq, 4); /* avoid AIX -O bug */ | |
197 | afs_DestroyReq(treq); | |
198 | ||
199 | afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc, | |
200 | ICL_TYPE_INT32, 999999); | |
201 | ||
202 | return code; | |
203 | } |