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