2 * Copyright 2000, International Business Machines Corporation and others.
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
9 * Portions Copyright (c) 2003 Apple Computer, Inc.
13 * afs_vnop_attrs.c - setattr and getattr vnodeops
25 #include <afsconfig.h>
26 #include "afs/param.h"
29 #include "afs/sysincludes.h" /* Standard vendor system headers */
30 #include "afsincludes.h" /* Afs-based standard headers */
31 #include "afs/afs_stats.h" /* statistics */
32 #include "afs/afs_cbqueue.h"
33 #include "afs/nfsclient.h"
34 #include "afs/afs_osidnlc.h"
36 extern afs_rwlock_t afs_xcbhash
;
37 struct afs_exporter
*afs_nfsexporter
;
38 extern struct vcache
*afs_globalVp
;
39 #if defined(AFS_HPUX110_ENV)
40 extern struct vfs
*afs_globalVFS
;
44 /* copy out attributes from cache entry */
46 afs_CopyOutAttrs(struct vcache
*avc
, struct vattr
*attrs
)
50 #if defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV)
51 struct vnode
*vp
= AFSTOV(avc
);
55 AFS_STATCNT(afs_CopyOutAttrs
);
56 if (afs_fakestat_enable
&& avc
->mvstat
== AFS_MVSTAT_MTPT
)
58 attrs
->va_type
= fakedir
? VDIR
: vType(avc
);
59 #if defined(AFS_SGI_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
60 attrs
->va_mode
= fakedir
? S_IFDIR
| 0755 : (mode_t
) (avc
->f
.m
.Mode
& 0xffff);
62 attrs
->va_mode
= fakedir
? VDIR
| 0755 : avc
->f
.m
.Mode
;
65 if (avc
->f
.m
.Mode
& (VSUID
| VSGID
)) {
66 /* setuid or setgid, make sure we're allowed to run them from this cell */
67 tcell
= afs_GetCell(avc
->f
.fid
.Cell
, 0);
68 if (tcell
&& (tcell
->states
& CNoSUID
))
69 attrs
->va_mode
&= ~(VSUID
| VSGID
);
71 #if defined(AFS_DARWIN_ENV)
73 if (!afs_darwin_realmodes
) {
74 /* Mac OS X uses the mode bits to determine whether a file or
75 * directory is accessible, and believes them, even though under
76 * AFS they're almost assuredly wrong, especially if the local uid
77 * does not match the AFS ID. So we set the mode bits
80 if (S_ISDIR(attrs
->va_mode
)) {
81 /* all access bits need to be set for directories, since even
82 * a mode 0 directory can still be used normally.
84 attrs
->va_mode
|= ACCESSPERMS
;
86 /* for other files, replicate the user bits to group and other */
87 mode_t ubits
= (attrs
->va_mode
& S_IRWXU
) >> 6;
88 attrs
->va_mode
|= ubits
| (ubits
<< 3);
92 #endif /* AFS_DARWIN_ENV */
93 attrs
->va_uid
= fakedir
? 0 : avc
->f
.m
.Owner
;
94 attrs
->va_gid
= fakedir
? 0 : avc
->f
.m
.Group
; /* yeah! */
95 #if defined(AFS_SUN5_ENV)
96 attrs
->va_fsid
= avc
->v
.v_vfsp
->vfs_fsid
.val
[0];
97 #elif defined(AFS_DARWIN80_ENV)
98 VATTR_RETURN(attrs
, va_fsid
, vfs_statfs(vnode_mount(AFSTOV(avc
)))->f_fsid
.val
[0]);
99 #elif defined(AFS_DARWIN_ENV)
100 attrs
->va_fsid
= avc
->v
->v_mount
->mnt_stat
.f_fsid
.val
[0];
101 #else /* ! AFS_DARWIN_ENV */
104 if (avc
->mvstat
== AFS_MVSTAT_ROOT
) {
105 tvp
= afs_GetVolume(&avc
->f
.fid
, 0, READ_LOCK
);
106 /* The mount point's vnode. */
109 afs_calc_inum(tvp
->mtpoint
.Cell
,
110 tvp
->mtpoint
.Fid
.Volume
,
111 tvp
->mtpoint
.Fid
.Vnode
);
112 if (FidCmp(&afs_rootFid
, &avc
->f
.fid
) && !attrs
->va_nodeid
)
113 attrs
->va_nodeid
= 2;
114 afs_PutVolume(tvp
, READ_LOCK
);
116 attrs
->va_nodeid
= 2;
119 afs_calc_inum(avc
->f
.fid
.Cell
,
120 avc
->f
.fid
.Fid
.Volume
,
121 avc
->f
.fid
.Fid
.Vnode
);
122 attrs
->va_nodeid
&= 0x7fffffff; /* Saber C hates negative inode #s! */
123 attrs
->va_nlink
= fakedir
? 100 : avc
->f
.m
.LinkCount
;
124 attrs
->va_size
= fakedir
? 4096 : avc
->f
.m
.Length
;
125 #if defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV)
126 vnode_pager_setsize(vp
, (u_long
) attrs
->va_size
);
128 attrs
->va_atime
.tv_sec
= attrs
->va_mtime
.tv_sec
= attrs
->va_ctime
.tv_sec
=
129 fakedir
? 0 : (int)avc
->f
.m
.Date
;
130 /* set microseconds to be dataversion # so that we approximate NFS-style
131 * use of mtime as a dataversion #. We take it mod 512K because
132 * microseconds *must* be less than a million, and 512K is the biggest
133 * power of 2 less than such. DataVersions are typically pretty small
134 * anyway, so the difference between 512K and 1000000 shouldn't matter
135 * much, and "&" is a lot faster than "%".
137 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
138 /* nfs on these systems puts an 0 in nsec and stores the nfs usec (aka
139 * dataversion) in va_gen */
141 attrs
->va_atime
.tv_nsec
= attrs
->va_mtime
.tv_nsec
=
142 attrs
->va_ctime
.tv_nsec
= 0;
143 attrs
->va_gen
= hgetlo(avc
->f
.m
.DataVersion
);
144 #elif defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_OBSD_ENV) || defined(AFS_NBSD_ENV)
145 attrs
->va_atime
.tv_nsec
= attrs
->va_mtime
.tv_nsec
=
146 attrs
->va_ctime
.tv_nsec
=
147 (hgetlo(avc
->f
.m
.DataVersion
) & 0x7ffff) * 1000;
149 attrs
->va_atime
.tv_usec
= attrs
->va_mtime
.tv_usec
=
150 attrs
->va_ctime
.tv_usec
= (hgetlo(avc
->f
.m
.DataVersion
) & 0x7ffff);
152 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
155 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
156 attrs
->va_blksize
= AFS_BLKSIZE
; /* XXX Was 8192 XXX */
158 attrs
->va_blocksize
= AFS_BLKSIZE
; /* XXX Was 8192 XXX */
161 #if defined(AFS_HPUX110_ENV)
163 attrs
->va_fstype
= afs_globalVFS
->vfs_mtype
;
167 * Below return 0 (and not 1) blocks if the file is zero length. This conforms
168 * better with the other filesystems that do return 0.
170 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
171 attrs
->va_bytes
= (attrs
->va_size
? (attrs
->va_size
+ 1023) : 1024);
173 attrs
->va_bytes_rsv
= -1;
175 #elif defined(AFS_HPUX_ENV)
176 attrs
->va_blocks
= (attrs
->va_size
? ((attrs
->va_size
+ 1023)>>10) : 0);
177 #elif defined(AFS_SGI_ENV)
178 attrs
->va_blocks
= BTOBB(attrs
->va_size
);
179 #elif defined(AFS_SUN5_ENV)
180 attrs
->va_nblocks
= (attrs
->va_size
? ((attrs
->va_size
+ 1023)>>10)<<1:0);
181 #else /* everything else */
182 attrs
->va_blocks
= (attrs
->va_size
? ((attrs
->va_size
+ 1023)>>10)<<1:0);
189 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
191 afs_getattr(OSI_VC_DECL(avc
), struct vattr
*attrs
, int flags
,
195 afs_getattr(OSI_VC_DECL(avc
), struct vattr
*attrs
, afs_ucred_t
*acred
)
199 struct vrequest
*treq
= NULL
;
204 AFS_STATCNT(afs_getattr
);
205 afs_Trace2(afs_iclSetp
, CM_TRACE_GETATTR
, ICL_TYPE_POINTER
, avc
,
206 ICL_TYPE_OFFSET
, ICL_HANDLE_OFFSET(avc
->f
.m
.Length
));
208 if (afs_fakestat_enable
&& avc
->mvstat
== AFS_MVSTAT_MTPT
) {
209 struct afs_fakestat_state fakestat
;
210 struct vrequest
*ureq
= NULL
;
212 code
= afs_CreateReq(&ureq
, acred
);
216 afs_InitFakeStat(&fakestat
);
217 code
= afs_TryEvalFakeStat(&avc
, &fakestat
, ureq
);
219 afs_PutFakeStat(&fakestat
);
220 afs_DestroyReq(ureq
);
224 code
= afs_CopyOutAttrs(avc
, attrs
);
225 afs_PutFakeStat(&fakestat
);
226 afs_DestroyReq(ureq
);
229 #if defined(AFS_SUN5_ENV)
230 if (flags
& ATTR_HINT
) {
231 code
= afs_CopyOutAttrs(avc
, attrs
);
235 #if defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)
236 if (avc
->f
.states
& CUBCinit
) {
237 code
= afs_CopyOutAttrs(avc
, attrs
);
244 if (afs_shuttingdown
!= AFS_RUNNING
) {
249 if (!(avc
->f
.states
& CStatd
)) {
250 if (!(code
= afs_CreateReq(&treq
, acred
))) {
251 code
= afs_VerifyVCache2(avc
, treq
);
257 #if defined(AFS_SUN5_ENV)
259 osi_FlushPages(avc
, acred
);
263 osi_FlushText(avc
); /* only needed to flush text if text locked last time */
264 code
= afs_CopyOutAttrs(avc
, attrs
);
266 if (afs_nfsexporter
) {
268 if ((code
= afs_CreateReq(&treq
, acred
))) {
273 if (AFS_NFSXLATORREQ(acred
)) {
274 if ((vType(avc
) != VDIR
)
275 && !afs_AccessOK(avc
, PRSFS_READ
, treq
,
277 CMB_ALLOW_EXEC_AS_READ
)) {
278 afs_DestroyReq(treq
);
282 if ((au
= afs_FindUser(treq
->uid
, -1, READ_LOCK
))) {
283 struct afs_exporter
*exporter
= au
->exporter
;
285 if (exporter
&& !(afs_nfsexporter
->exp_states
& EXP_UNIXMODE
)) {
288 * If the remote user wishes to enforce default Unix mode semantics,
289 * like in the nfs exporter case, we OR in the user bits
290 * into the group and other bits. We need to do this
291 * because there is no RFS_ACCESS call and thus nfs
292 * clients implement nfs_access by interpreting the
293 * mode bits in the traditional way, which of course
296 ubits
= (attrs
->va_mode
& 0700) >> 6;
297 attrs
->va_mode
= attrs
->va_mode
| ubits
| (ubits
<< 3);
298 /* If it's the root of AFS, replace the inode number with the
299 * inode number of the mounted on directory; otherwise this
300 * confuses getwd()... */
301 #ifdef AFS_LINUX22_ENV
302 if (avc
== afs_globalVp
) {
303 struct inode
*ip
= AFSTOV(avc
)->i_sb
->s_root
->d_inode
;
304 attrs
->va_nodeid
= ip
->i_ino
; /* VTOI()? */
308 #if defined(AFS_DARWIN_ENV)
309 vnode_isvroot(AFSTOV(avc
))
310 #elif defined(AFS_NBSD50_ENV)
311 AFSTOV(avc
)->v_vflag
& VV_ROOT
313 AFSTOV(avc
)->v_flag
& VROOT
316 struct vnode
*vp
= AFSTOV(avc
);
318 #ifdef AFS_DARWIN80_ENV
319 /* XXX vp = vnode_mount(vp)->mnt_vnodecovered; */
322 vp
= vp
->v_vfsp
->vfs_vnodecovered
;
323 if (vp
) { /* Ignore weird failures */
325 attrs
->va_nodeid
= VnodeToIno(vp
);
329 ip
= (struct inode
*)VTOI(vp
);
330 if (ip
) /* Ignore weird failures */
331 attrs
->va_nodeid
= ip
->i_number
;
336 #endif /* AFS_LINUX22_ENV */
338 afs_PutUser(au
, READ_LOCK
);
346 afs_DestroyReq(treq
);
349 code
= afs_CheckCode(code
, treq
, 14);
350 afs_DestroyReq(treq
);
354 /* convert a Unix request into a status store request */
356 afs_VAttrToAS(struct vcache
*avc
, struct vattr
*av
,
357 struct AFSStoreStatus
*as
)
362 AFS_STATCNT(afs_VAttrToAS
);
363 #if defined(AFS_DARWIN80_ENV)
364 if (VATTR_IS_ACTIVE(av
, va_mode
)) {
365 #elif defined(AFS_AIX_ENV)
366 /* Boy, was this machine dependent bogosity hard to swallow????.... */
367 if (av
->va_mode
!= -1) {
368 #elif defined(AFS_LINUX22_ENV) || defined(UKERNEL)
369 if (av
->va_mask
& ATTR_MODE
) {
370 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
371 if (av
->va_mask
& AT_MODE
) {
372 #elif defined(AFS_XBSD_ENV)
373 if (av
->va_mode
!= (mode_t
)VNOVAL
) {
375 if (av
->va_mode
!= ((unsigned short)-1)) {
378 as
->UnixModeBits
= av
->va_mode
& 0xffff;
379 if (avc
->f
.states
& CForeign
) {
380 ObtainWriteLock(&avc
->lock
, 127);
381 afs_FreeAllAxs(&(avc
->Access
));
382 ReleaseWriteLock(&avc
->lock
);
385 #if defined(AFS_DARWIN80_ENV)
386 if (VATTR_IS_ACTIVE(av
, va_gid
)) {
387 #elif defined(AFS_LINUX22_ENV) || defined(UKERNEL)
388 if (av
->va_mask
& ATTR_GID
) {
389 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
390 if (av
->va_mask
& AT_GID
) {
391 #elif defined(AFS_HPUX_ENV)
392 #if defined(AFS_HPUX102_ENV)
393 if (av
->va_gid
!= GID_NO_CHANGE
) {
395 if (av
->va_gid
!= ((unsigned short)-1)) {
397 #elif defined(AFS_XBSD_ENV)
398 if (av
->va_gid
!= (gid_t
)VNOVAL
) {
400 if (av
->va_gid
!= -1) {
401 #endif /* AFS_LINUX22_ENV */
402 mask
|= AFS_SETGROUP
;
403 as
->Group
= av
->va_gid
;
405 #if defined(AFS_DARWIN80_ENV)
406 if (VATTR_IS_ACTIVE(av
, va_uid
)) {
407 #elif defined(AFS_LINUX22_ENV) || defined(UKERNEL)
408 if (av
->va_mask
& ATTR_UID
) {
409 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
410 if (av
->va_mask
& AT_UID
) {
411 #elif defined(AFS_HPUX_ENV)
412 #if defined(AFS_HPUX102_ENV)
413 if (av
->va_uid
!= UID_NO_CHANGE
) {
414 #elif defined(AFS_XBSD_ENV)
415 if (av
->va_uid
!= (uid_t
)VNOVAL
) {
417 if (av
->va_uid
!= ((unsigned short)-1)) {
420 if (av
->va_uid
!= -1) {
421 #endif /* AFS_LINUX22_ENV */
422 mask
|= AFS_SETOWNER
;
423 as
->Owner
= av
->va_uid
;
425 #if defined(AFS_DARWIN80_ENV)
426 if (VATTR_IS_ACTIVE(av
, va_modify_time
)) {
427 #elif defined(AFS_LINUX22_ENV) || defined(UKERNEL)
428 if (av
->va_mask
& ATTR_MTIME
) {
429 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
430 if (av
->va_mask
& AT_MTIME
) {
432 if (av
->va_mtime
.tv_sec
!= -1) {
434 mask
|= AFS_SETMODTIME
;
436 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
437 if (av
->va_mtime
.tv_nsec
== -1)
439 if (av
->va_mtime
.tv_usec
== -1)
441 as
->ClientModTime
= osi_Time(); /* special Sys V compat hack for Suns */
444 as
->ClientModTime
= av
->va_mtime
.tv_sec
;
450 /* We don't set CDirty bit in avc->f.states because setattr calls WriteVCache
451 * synchronously, therefore, it's not needed.
453 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
455 afs_setattr(OSI_VC_DECL(avc
), struct vattr
*attrs
, int flags
,
459 afs_setattr(OSI_VC_DECL(avc
), struct vattr
*attrs
,
463 struct vrequest
*treq
= NULL
;
464 struct AFSStoreStatus astat
;
466 #if defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV)
467 struct vnode
*vp
= AFSTOV(avc
);
469 struct afs_fakestat_state fakestate
;
472 AFS_STATCNT(afs_setattr
);
473 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_LINUX22_ENV)
474 afs_Trace4(afs_iclSetp
, CM_TRACE_SETATTR
, ICL_TYPE_POINTER
, avc
,
475 ICL_TYPE_INT32
, attrs
->va_mask
, ICL_TYPE_OFFSET
,
476 ICL_HANDLE_OFFSET(attrs
->va_size
), ICL_TYPE_OFFSET
,
477 ICL_HANDLE_OFFSET(avc
->f
.m
.Length
));
479 afs_Trace4(afs_iclSetp
, CM_TRACE_SETATTR
, ICL_TYPE_POINTER
, avc
,
480 ICL_TYPE_INT32
, attrs
->va_mode
, ICL_TYPE_OFFSET
,
481 ICL_HANDLE_OFFSET(attrs
->va_size
), ICL_TYPE_OFFSET
,
482 ICL_HANDLE_OFFSET(avc
->f
.m
.Length
));
484 if ((code
= afs_CreateReq(&treq
, acred
)))
487 memset(&astat
, 0, sizeof(astat
));
491 afs_InitFakeStat(&fakestate
);
492 code
= afs_EvalFakeStat(&avc
, &fakestate
, treq
);
496 if (avc
->f
.states
& CRO
) {
500 #if defined(AFS_SGI_ENV)
501 /* ignore ATTR_LAZY calls - they are really only for keeping
502 * the access/mtime of mmaped files up to date
504 if (flags
& ATTR_LAZY
)
507 /* if file size has changed, we need write access, otherwise (e.g.
508 * chmod) give it a shot; if it fails, we'll discard the status
511 #if defined(AFS_DARWIN80_ENV)
512 if (VATTR_IS_ACTIVE(attrs
, va_data_size
)) {
513 #elif defined(AFS_LINUX22_ENV) || defined(UKERNEL)
514 if (attrs
->va_mask
& ATTR_SIZE
) {
515 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
516 if (attrs
->va_mask
& AT_SIZE
) {
517 #elif defined(AFS_XBSD_ENV)
518 if (attrs
->va_size
!= VNOVAL
) {
519 #elif defined(AFS_AIX41_ENV)
520 if (attrs
->va_size
!= -1) {
522 if (attrs
->va_size
!= ~0) {
524 if (!afs_AccessOK(avc
, PRSFS_WRITE
, treq
, DONT_CHECK_MODE_BITS
)) {
530 if (AFS_IS_DISCONNECTED
&& !AFS_IS_DISCON_RW
) {
535 afs_VAttrToAS(avc
, attrs
, &astat
); /* interpret request */
537 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
538 if (AFS_NFSXLATORREQ(acred
)) {
539 avc
->execsOrWriters
++;
543 #if defined(AFS_SGI_ENV)
544 AFS_RWLOCK((vnode_t
*) avc
, VRWLOCK_WRITE
);
546 #if defined(AFS_DARWIN80_ENV)
547 if (VATTR_IS_ACTIVE(attrs
, va_data_size
)) {
548 #elif defined(AFS_LINUX22_ENV) || defined(UKERNEL)
549 if (attrs
->va_mask
& ATTR_SIZE
) {
550 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
551 if (attrs
->va_mask
& AT_SIZE
) {
552 #elif defined(AFS_XBSD_ENV)
553 if (attrs
->va_size
!= VNOVAL
) {
554 #elif defined(AFS_AIX41_ENV)
555 if (attrs
->va_size
!= -1) {
557 if (attrs
->va_size
!= ~0) {
559 afs_size_t tsize
= attrs
->va_size
;
560 ObtainWriteLock(&avc
->lock
, 128);
561 avc
->f
.states
|= CDirty
;
563 if (AFS_IS_DISCONNECTED
&& tsize
>=avc
->f
.m
.Length
) {
564 /* If we're growing the file, and we're disconnected, we need
565 * to make the relevant dcache chunks appear ourselves. */
566 code
= afs_ExtendSegments(avc
, tsize
, treq
);
568 code
= afs_TruncateAllSegments(avc
, tsize
, treq
, acred
);
570 #ifdef AFS_LINUX26_ENV
571 /* We must update the Linux kernel's idea of file size as soon as
572 * possible, to avoid racing with delayed writepages delivered by
575 i_size_write(AFSTOV(avc
), tsize
);
577 #if defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV)
578 vnode_pager_setsize(vp
, (u_long
) tsize
);
580 /* if date not explicitly set by this call, set it ourselves, since we
581 * changed the data */
582 if (!(astat
.Mask
& AFS_SETMODTIME
)) {
583 astat
.Mask
|= AFS_SETMODTIME
;
584 astat
.ClientModTime
= osi_Time();
588 if (((avc
->execsOrWriters
<= 0) && (avc
->f
.states
& CCreating
) == 0)
589 || (avc
->execsOrWriters
== 1 && AFS_NFSXLATORREQ(acred
))) {
591 /* Store files now if not disconnected. */
592 /* XXX: AFS_IS_DISCON_RW handled. */
593 if (!AFS_IS_DISCONNECTED
) {
594 code
= afs_StoreAllSegments(avc
, treq
, AFS_ASYNC
);
596 avc
->f
.states
&= ~CDirty
;
600 avc
->f
.states
&= ~CDirty
;
602 ReleaseWriteLock(&avc
->lock
);
604 osi_FlushText(avc
); /* do this after releasing all locks */
607 if (!AFS_IS_DISCONNECTED
) {
609 ObtainSharedLock(&avc
->lock
, 16); /* lock entry */
610 code
= afs_WriteVCache(avc
, &astat
, treq
); /* send request */
611 ReleaseSharedLock(&avc
->lock
); /* release lock */
614 /* error? erase any changes we made to vcache entry */
615 afs_StaleVCache(avc
);
618 ObtainSharedLock(&avc
->lock
, 712);
619 /* Write changes locally. */
620 code
= afs_WriteVCacheDiscon(avc
, &astat
, attrs
);
621 ReleaseSharedLock(&avc
->lock
);
622 } /* if (!AFS_IS_DISCONNECTED) */
624 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
625 if (AFS_NFSXLATORREQ(acred
)) {
626 avc
->execsOrWriters
--;
629 #if defined(AFS_SGI_ENV)
630 AFS_RWUNLOCK((vnode_t
*) avc
, VRWLOCK_WRITE
);
633 afs_PutFakeStat(&fakestate
);
636 code
= afs_CheckCode(code
, treq
, 15);
637 afs_DestroyReq(treq
);
644 * \note The caller must free the allocated vattr with
645 * afs_DestroyAttr() if this function returns successfully (zero).
647 * \note The GLOCK must be held on platforms which require the GLOCK
648 * for osi_AllocSmallSpace() and osi_FreeSmallSpace().
650 * \param[out] out address of the vattr pointer
651 * \return 0 on success
654 afs_CreateAttr(struct vattr
**out
)
656 struct vattr
*vattr
= NULL
;
661 vattr
= osi_AllocSmallSpace(sizeof(struct vattr
));
665 memset(vattr
, 0, sizeof(struct vattr
));
671 * Deallocate a vattr.
673 * \note The GLOCK must be held on platforms which require the GLOCK
674 * for osi_FreeSmallSpace().
676 * \param[in] vattr pointer to the vattr to free; may be NULL
679 afs_DestroyAttr(struct vattr
*vattr
)
682 osi_FreeSmallSpace(vattr
);