Import Upstream version 1.8.5
[hcoop/debian/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 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 }