08502f5a975c64dd2eab18a7231298c019e4cb7d
[openafs.git] / src / afs / IRIX / osi_inode.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  * IRIX inode operations
12  *
13  * Implements:
14  * afsdptoip
15  * afsiptodp
16  * afsidestroy
17  * getinode
18  * igetinode
19  * xfs_getinode
20  * xfs_igetinode
21  * icreate
22  * afs_syscall_icreate
23  * xfs_icreatename64
24  * afs_syscall_icreatename64
25  * iopenargs64
26  * afs_syscall_iopen
27  * iopen
28  * iopen64
29  * efs_iincdec
30  * xfs_iincdec64
31  * iincdec64
32  * afs_syscall_idec64
33  * afs_syscall_iinc64
34  * iincdec
35  * iinc
36  * idec
37  * afs_syscall_iincdec
38  * afs_syscall_ilistinode64
39  *
40  */
41
42 #include "../afs/param.h"       /* Should be always first */
43 #include "../afs/sysincludes.h" /* Standard vendor system headers */
44 #include "../afs/afsincludes.h" /* Afs-based standard headers */
45 #include "../afs/osi_inode.h"
46 #include "../afs/afs_stats.h" /* statistics stuff */
47
48 #define BAD_IGET        -1000
49
50 /*
51  * SGI dependent system calls
52  */
53 #ifndef INODESPECIAL
54 /*
55  * `INODESPECIAL' type inodes are ones that describe volumes.
56  */
57 #define INODESPECIAL    0xffffffff      /* ... from ../vol/viceinode.h  */
58 #endif
59 /*
60  * copy disk inode to incore inode and vice-versa
61  */
62 void
63 afsdptoip(struct efs_dinode *dp, struct inode *ip)
64 {
65         struct afsparms *ap;
66
67         ip->i_afs = kmem_alloc(sizeof(struct afsparms), KM_SLEEP);
68         osi_Assert(ip->i_version == EFS_IVER_AFSSPEC
69                || ip->i_version == EFS_IVER_AFSINO); 
70         ap = (struct afsparms *)ip->i_afs;
71         /* vicep1 is VOLid */
72         ap->vicep1 = dmag(dp, 0) << 24 | dmag(dp, 1) << 16 |
73                                           dmag(dp, 2) << 8 | dmag(dp, 3) << 0;
74                                            
75         if (ip->i_version == EFS_IVER_AFSSPEC) {
76                 ap->vicep3 = dmag(dp, 8);       /* Type */
77                 ap->vicep4 = dmag(dp, 4) << 24 | dmag(dp, 5) << 16 |
78                                           dmag(dp, 6) << 8 | dmag(dp, 7) << 0;
79
80         } else {
81                 /* vnode number */
82                 ap->vicep2 = dmag(dp, 4) << 16 |
83                                           dmag(dp, 5) << 8 | dmag(dp, 6) << 0;
84                 /* disk uniqifier */
85                 ap->vicep3 = dmag(dp, 7) << 16 |
86                                           dmag(dp, 8) << 8 | dmag(dp, 9) << 0;
87                 /* data version */
88                 ap->vicep4 = dmag(dp, 10) << 16 |
89                                           dmag(dp, 11) << 8 | (dp)->di_spare;
90         }
91 }
92
93 void
94 afsiptodp(struct inode *ip, struct efs_dinode *dp)
95 {
96         struct afsparms *ap;
97
98         if (ip->i_afs == NULL)
99                 return;
100
101         osi_Assert(ip->i_version == EFS_IVER_AFSSPEC
102                || ip->i_version == EFS_IVER_AFSINO); 
103         ap = (struct afsparms *)ip->i_afs;
104         /* vicep1 is VOLid */
105         dmag(dp, 0) = ap->vicep1 >> 24;
106         dmag(dp, 1) = ap->vicep1 >> 16;
107         dmag(dp, 2) = ap->vicep1 >> 8;
108         dmag(dp, 3) = ap->vicep1 >> 0;
109                                            
110         if (ip->i_version == EFS_IVER_AFSSPEC) {
111                 /* Type */
112                 dmag(dp, 8) = ap->vicep3;
113                 /* ParentId */
114                 dmag(dp, 4) = ap->vicep4 >> 24;
115                 dmag(dp, 5) = ap->vicep4 >> 16;
116                 dmag(dp, 6) = ap->vicep4 >> 8;
117                 dmag(dp, 7) = ap->vicep4 >> 0;
118         } else {
119                 /* vnode number */
120                 dmag(dp, 4) = ap->vicep2 >> 16;
121                 dmag(dp, 5) = ap->vicep2 >> 8;
122                 dmag(dp, 6) = ap->vicep2 >> 0;
123                 /* disk uniqifier */
124                 dmag(dp, 7) = ap->vicep3 >> 16;
125                 dmag(dp, 8) = ap->vicep3 >> 8;
126                 dmag(dp, 9) = ap->vicep3 >> 0;
127                 /* data version */
128                 dmag(dp, 10) = ap->vicep4 >> 16;
129                 dmag(dp, 11) = ap->vicep4 >> 8;
130                 dp->di_spare = ap->vicep4 >> 0;
131         }
132 }
133
134 void
135 afsidestroy(struct inode *ip)
136 {
137         if (ip->i_afs) {
138                 kmem_free(ip->i_afs, sizeof(struct afsparms));
139                 ip->i_afs = NULL;
140         }
141 }
142
143 extern int efs_fstype;
144 #ifdef AFS_SGI_XFS_IOPS_ENV
145 extern int xfs_fstype;
146 #endif
147
148 int
149 getinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct inode **ipp)
150 {
151     struct inode *ip;
152     int error;
153
154     if (!vfsp) {
155 #ifdef AFS_SGI65_ENV
156         vfsp = vfs_devsearch(dev, efs_fstype);
157 #else
158         vfsp = vfs_devsearch(dev);
159 #endif
160         if (!vfsp) {
161             return ENXIO;
162         }
163     }
164 #ifndef AFS_SGI65_ENV
165     if (vfsp->vfs_fstype != efs_fstype)
166         return ENOSYS;
167 #endif
168
169     if (error = iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)), 
170                      (unsigned int)(inode&0xffffffff), &ip)) {
171         return error;
172     }
173     *ipp = ip;
174     return 0;
175 }
176
177 int
178 igetinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct inode **ipp)
179 {
180     struct inode *ip;
181     int error;
182
183     AFS_STATCNT(igetinode);
184     if (error = getinode(vfsp, dev, inode, &ip))
185         return error;
186     *ipp = ip;
187     return 0;
188 }
189
190 int XFS_IGET_EPOS;
191 ino_t XFS_IGET_INO;
192 dev_t XFS_IGET_DEV;
193 #define SET_XFS_ERROR(POS, DEV, INO) \
194         XFS_IGET_EPOS = (POS), XFS_IGET_DEV = (DEV), XFS_IGET_INO = (INO)
195
196 int xfs_getinode(struct vfs *vfsp, dev_t dev, ino_t inode,
197                  struct xfs_inode **ipp)
198 {
199     struct xfs_inode *ip;
200     int error;
201
202     if (!vfsp) {
203 #ifdef AFS_SGI65_ENV
204         vfsp = vfs_devsearch(dev, xfs_fstype);
205 #else
206         vfsp = vfs_devsearch(dev);
207 #endif
208         if (!vfsp) {
209             SET_XFS_ERROR(1, dev, inode);
210             return ENXIO;
211         }
212     }
213 #ifndef AFS_SGI65_ENV
214     if (vfsp->vfs_fstype != xfs_fstype) {
215         SET_XFS_ERROR(2, vfsp->vfs_dev, inode);
216         return ENOSYS;
217     }
218 #endif
219
220     if (error = xfs_iget((((struct mount *)
221                            ((vfsp)->vfs_bh.bh_first)->bd_pdata)),
222                          (void*)0, (xfs_ino_t)inode, 
223                          XFS_ILOCK_SHARED, &ip, (daddr_t)0)) {
224         SET_XFS_ERROR(3, vfsp->vfs_dev, inode);
225         return error;
226     }
227
228     *ipp = ip;
229     return 0;
230 }
231
232 /* xfs_igetinode now returns an unlocked inode. This is fine, since we
233  * have a refcount on the holding vnode.
234  */
235 int xfs_igetinode(struct vfs *vfsp, dev_t dev, ino_t inode,
236                   struct xfs_inode **ipp)
237 {
238     struct xfs_inode *ip;
239     vnode_t *vp;
240     vattr_t vattr;
241     int error;
242
243     AFS_STATCNT(igetinode);
244
245     *ipp = NULL;
246     if (error = xfs_getinode(vfsp, dev, inode, &ip)) {
247         return error;
248     }
249
250     xfs_iunlock(ip, XFS_ILOCK_SHARED);
251     vp = XFS_ITOV(ip);
252     vattr.va_mask = AT_STAT;
253     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), error);
254     if (error) {
255         SET_XFS_ERROR(4, vp->v_vfsp->vfs_dev, inode);
256         VN_RELE(vp);
257         return error;
258     }
259     if (vattr.va_nlink == 0 || vattr.va_type != VREG) {
260         SET_XFS_ERROR(5, vp->v_vfsp->vfs_dev, inode);
261         VN_RELE(vp);
262         return ENOENT;
263     }
264
265     *ipp = ip;
266     return 0;
267 }
268
269 /**************************************************************************
270  * inode creation routines.
271  *
272  ***************************************************************************/
273 struct icreateargs {
274         sysarg_t        dev;
275         sysarg_t        near_inode;
276         sysarg_t        param1;
277         sysarg_t        param2;
278         sysarg_t        param3;
279         sysarg_t        param4;
280 };
281
282 /* EFS only fs suite uses this entry point - icreate in afssyscalls.c. */
283 #ifdef AFS_SGI_EFS_IOPS_ENV
284 int
285 icreate(struct icreateargs *uap, rval_t *rvp)
286 {
287     AFS_STATCNT(icreate);
288     return(afs_syscall_icreate(uap->dev, uap->near_inode, uap->param1,
289                                uap->param2, uap->param3, uap->param4, rvp));
290 }
291
292 int
293 afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp)
294 afs_uint32 dev, near_inode, param1, param2, param3, param4;
295 rval_t *rvp;
296 {
297         struct inode *ip, *newip;
298         struct afsparms *ap;
299         struct cred cr;
300         int error;
301
302         AFS_STATCNT(afs_syscall_icreate);
303         if (!afs_suser())
304                 return EPERM;
305
306         if (error = getinode(0, (dev_t)dev, 2, &ip))
307                 return error;
308
309         cr.cr_uid = 0;
310         cr.cr_gid = -2;
311         if (error = efs_ialloc(ip, IFREG, 1, NODEV, &newip, &cr)) {     
312             iput(ip);
313             return error;
314         }
315         iput(ip);
316         osi_Assert(newip);
317         newip->i_flags |= IACC|IUPD|ICHG;
318
319         osi_Assert(newip->i_afs == NULL);
320         newip->i_afs = kmem_alloc(sizeof(struct afsparms), KM_SLEEP);
321         if (param2 == INODESPECIAL)
322                 newip->i_version = EFS_IVER_AFSSPEC;
323         else
324                 newip->i_version = EFS_IVER_AFSINO;
325         ap = (struct afsparms *)newip->i_afs;
326         ap->vicep1 = param1;    /* VOLid */
327         ap->vicep2 = param2;    /* Vnode # */
328         ap->vicep3 = param3;    /* SPEC:type INO:vnode uniq */
329         ap->vicep4 = param4;    /* SPEC:parentId INO:data version */
330         rvp->r_val1 = newip->i_number;
331         iput(newip);
332         return 0;
333 }
334 #else /* !AFS_SGI_EFS_IOPS_ENV */
335 int
336 afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp)
337 afs_uint32 dev, near_inode, param1, param2, param3, param4;
338 rval_t *rvp;
339 {
340     return ENOSYS;
341 }
342 #endif /* AFS_SGI_EFS_IOPS_ENV */
343
344 #ifdef AFS_SGI_XFS_IOPS_ENV
345 /* inode creation routines for icreatename64 entry point. Use for EFS/XFS
346  * fileserver suite.  For XFS, create a name in the namespace as well as the
347  * inode. For EFS, just call the original routine.
348  */
349
350 #include <afs/xfsattrs.h>
351 #include <sys/attributes.h>
352
353 extern char *int_to_base64(char *, int);
354
355 /* Lock against races creating/removing directory - vos zap RO, vos create RW*/
356 kmutex_t afs_vol_create_lock;
357 int afs_vol_create_lock_inited = 0;
358 #define AFS_LOCK_VOL_CREATE() { \
359         if (!afs_vol_create_lock_inited) { \
360             mutex_init(&afs_vol_create_lock, MUTEX_DEFAULT, \
361                        "afs_vol_create_lock"); \
362             afs_vol_create_lock_inited = 1; \
363         } \
364         mutex_enter(&afs_vol_create_lock); \
365                                  }
366 #define AFS_UNLOCK_VOL_CREATE() mutex_exit(&afs_vol_create_lock)
367
368
369 /* xfs_icreatename64
370  * Create an AFS inode in the XFS name space. If required create the proper
371  * containing directory. See sys/xfsattrs.h for the details on the naming
372  * conventions and the usage of file and directory attributes.
373  *
374  * The inode parameters are stored in an XFS attribute called "AFS". In
375  * addition gid is set to XFS_VICEMAGIC and uid is set to the low 31 bits
376  * of the RW volume id. This is so inode verification in iinc and idec
377  * don't need to get the attribute. Note that only the low 31 bits are set.
378  * This is because chmod only accepts up to MAX_UID and chmod is used
379  * to correct these values in xfs_ListViceInodes.
380  */
381 int
382 xfs_icreatename64(struct vfs *vfsp, int datap, int datalen,
383                   afs_inode_params_t params, ino_t *inop)
384 {
385 #define AFS_PNAME_SIZE 16
386     char path[64];
387     char name[64];
388     b64_string_t stmp1, stmp2;
389     afs_xfs_attr_t attrs;
390     struct vattr vattr;
391     int name_version = AFS_XFS_NAME_VERS;
392     int code = 0, unused;
393     struct vnode *vp;
394     struct vnode *dvp;
395     int rw_vno;         /* volume ID of parent volume */
396     int i;
397     int createdDir = 0;
398     size_t junk;
399     char *s;
400
401
402     /* Get vnode for directory which will contain new inode. */
403     if (datalen >= AFS_PNAME_SIZE)
404         return E2BIG;
405
406     AFS_COPYINSTR((char*)datap, path, AFS_PNAME_SIZE-1, &junk, unused);
407     if (*path != '/') {
408         return EINVAL;
409     }
410
411     rw_vno = (params[1] == INODESPECIAL) ? params[3] : params[0];
412
413     /* directory name */
414     strcat(path, "/");
415     strcat(path, AFS_INODE_DIR_NAME);
416     strcat(path, int_to_base64(stmp1, rw_vno));
417
418     if (params[1] == INODESPECIAL)
419         AFS_LOCK_VOL_CREATE();
420
421     code = gop_lookupname(path, AFS_UIOSYS, FOLLOW, (struct vnode **) 0, &dvp);
422     if (code == ENOENT) {
423         /* Maybe it's an old directory name format. */
424         AFS_COPYINSTR((char*)datap, name, AFS_PNAME_SIZE-1, &junk, unused);
425         strcat(name, "/.");
426         strcat(name, int_to_base64(stmp1, rw_vno));
427         code = gop_lookupname(name, AFS_UIOSYS, FOLLOW, (struct vnode **) 0,
428                               &dvp);
429         if (!code) {
430             /* Use old name format. */
431             strcpy(path, name);
432             name_version = AFS_XFS_NAME_VERS1;
433         }
434     }
435
436     if (code == ENOENT) {
437         afs_xfs_dattr_t dattr;
438         /* make directory. */
439         
440         code = AFS_VN_OPEN(path, UIO_SYSSPACE, FCREAT|FEXCL, 0700, &dvp,
441                            CRMKDIR);
442         if (code) {
443             if (code == EEXIST) {
444                 /* someone beat us to it? */
445                 code = gop_lookupname(path, AFS_UIOSYS, 0, (struct vnode **) 0,
446                                       &dvp);
447             }
448             if (code) {
449                 AFS_UNLOCK_VOL_CREATE();
450                 return code;
451             }
452         }
453         else
454             createdDir = 1;
455         bzero((char*)&dattr, sizeof(dattr));
456         dattr.atd_version = AFS_XFS_ATD_VERS;
457         dattr.atd_volume = rw_vno;
458         AFS_VOP_ATTR_SET(dvp, AFS_XFS_DATTR, (char*)&dattr,
459                          SIZEOF_XFS_DATTR_T,
460                          ATTR_ROOT|ATTR_CREATE, OSI_GET_CURRENT_CRED(), code);
461         if (code) {
462             VN_RELE(dvp);
463             if (createdDir)
464                 (void) vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
465             AFS_UNLOCK_VOL_CREATE();
466             return code;
467         }
468     }
469
470     vattr.va_mask = AT_FSID|AT_NODEID; /* gets a guick return using FSID*/
471     AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
472     if (code) {
473         VN_RELE(dvp);
474         return code;
475     }
476
477     bzero((char*)&attrs, sizeof(attrs));
478     attrs.at_pino = vattr.va_nodeid;
479     VN_RELE(dvp);
480         
481     /* Create the desired file. Use up to ten tries to create a unique name. */
482     (void) strcpy(name, path);
483     (void) strcat(name, "/.");
484     (void) strcat(name, int_to_base64(stmp2, params[2]));
485     s = &name[strlen(name)];
486
487     attrs.at_tag = 0;    /* Initial guess at a unique tag. */
488     for (i=0; i<10; i++) {
489             *s = '\0';
490             strcat(s, ".");
491             strcat(s, int_to_base64(stmp1, attrs.at_tag));
492         code = AFS_VN_OPEN(name, UIO_SYSSPACE, FCREAT|FEXCL, 0600, &vp,
493                            CRCREAT);
494         if (!code || code != EEXIST)
495             break;
496
497         attrs.at_tag ++ ;
498     }
499     /* Unlock the creation process since the directory now has a file in it.*/
500     if (params[1] == INODESPECIAL)
501         AFS_UNLOCK_VOL_CREATE();
502         
503     if (!code) {
504         /* Set attributes. */
505         bcopy((char*)params, (char*)attrs.at_param,
506               sizeof(afs_inode_params_t));
507         attrs.at_attr_version = AFS_XFS_ATTR_VERS;
508         attrs.at_name_version = name_version;
509         AFS_VOP_ATTR_SET(vp, AFS_XFS_ATTR, (char*)&attrs,
510                          SIZEOF_XFS_ATTR_T,
511                          ATTR_ROOT|ATTR_CREATE, OSI_GET_CURRENT_CRED(),
512                          code);
513         if (!code) {
514             vattr.va_mode = 1;
515             vattr.va_uid = AFS_XFS_VNO_CLIP(params[0]);
516             vattr.va_gid = XFS_VICEMAGIC;
517             vattr.va_mask = AT_MODE | AT_UID | AT_GID;
518             AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
519         }
520         if (!code) {
521             vattr.va_mask = AT_NODEID;
522             AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
523         }
524         if (!code)
525             *inop = vattr.va_nodeid;
526         VN_RELE(vp);
527     }
528
529     if (code) {
530         /* remove partially created file. */
531         (void) vn_remove(name, UIO_SYSSPACE, RMFILE);
532         
533         /* and directory if volume special file. */
534         if (createdDir) {
535             AFS_LOCK_VOL_CREATE();
536             (void) vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
537             AFS_UNLOCK_VOL_CREATE();
538         }
539     }
540     return code;
541 }
542
543 /* afs_syscall_icreatename64
544  * This is the icreatename64 entry point used by the combined EFS/XFS
545  * fileserver suite. The datap and datalen do not need to be set for EFS.
546  */
547 int
548 afs_syscall_icreatename64(int dev, int datap, int datalen, int paramp,
549                           int inop)
550 {
551     struct vfs *vfsp;
552     afs_inode_params_t param;
553     int code;
554     rval_t rval;
555     ino_t ino;
556
557
558     if (!afs_suser())
559         return EPERM;
560
561 #ifdef AFS_SGI65_ENV
562     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
563 #else
564     vfsp = vfs_devsearch(dev);
565 #endif
566     if (vfsp == NULL) {
567         return ENXIO;
568     }
569
570     AFS_COPYIN((char*)paramp, (char*)param, sizeof(afs_inode_params_t), code);
571     if (vfsp->vfs_fstype == xfs_fstype) {
572         code =  xfs_icreatename64(vfsp, datap, datalen, param, &ino);
573         if (code)
574             return code;
575         else {
576             AFS_COPYOUT((char*)&ino, (char*)inop, sizeof(ino_t), code);
577             return code;
578         }
579     }
580     else if (vfsp->vfs_fstype == efs_fstype) {
581         code = afs_syscall_icreate(dev, 0, param[0], param[1], param[2],
582                                    param[3], &rval);
583         if (code)
584             return code;
585         else {
586             ino = (ino_t)rval.r_val1;
587             AFS_COPYOUT((char*)&ino, (char*)inop, sizeof(ino_t), code);
588             return code;
589         }
590     }
591     return ENXIO;
592 }
593 #endif /* AFS_SGI_XFS_IOPS_ENV */
594
595 /*
596  * iopen system calls -- open an inode for reading/writing
597  * Restricted to super user.
598  * Any IFREG files.
599  * The original EFS only system calls are still present in the kernel for
600  * in case a kernel upgrade is done for a fix, but the EFS fileserver is
601  * still in use.
602  */
603 struct iopenargs {
604         sysarg_t        dev;
605         sysarg_t        inode;
606         sysarg_t        usrmod;
607 };
608
609 #ifdef AFS_SGI_XFS_IOPS_ENV
610 struct iopenargs64 {
611         sysarg_t        dev;
612         sysarg_t        inode_hi;
613         sysarg_t        inode_lo;
614         sysarg_t        usrmod;
615 };
616
617 #ifdef AFS_SGI65_ENV
618 int
619 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t *rvp)
620 {
621         struct file *fp;
622         int fd;
623         int error;
624         struct vfs* vfsp;
625         struct vnode *vp;
626
627         AFS_STATCNT(afs_syscall_iopen);
628         if (!afs_suser())
629                 return EPERM;
630         vfsp = vfs_devsearch(dev, xfs_fstype);
631         if (!vfsp)
632             vfsp = vfs_devsearch(dev, efs_fstype);
633         if (!vfsp)
634             return ENXIO;
635
636 #ifdef AFS_SGI_EFS_IOPS_ENV
637         if (vfsp->vfs_fstype == efs_fstype) {
638             struct inode *ip;
639             if (error = igetinode(vfsp, (dev_t)dev, inode, &ip))
640                 return error;
641             vp = EFS_ITOV(ip);
642             if (error = vfile_alloc((usrmod+1) & (FMASK), &fp, &fd)) {
643                 iput(ip);
644                 return error;
645             }
646             iunlock(ip);
647         }
648         else 
649 #endif /* AFS_SGI_EFS_IOPS_ENV */
650           if (vfsp->vfs_fstype == xfs_fstype) {
651               struct xfs_inode *xip;
652               if (error = xfs_igetinode(vfsp, (dev_t)dev, inode, &xip))
653                   return error;
654               vp = XFS_ITOV(xip);
655               if (error = vfile_alloc((usrmod+1) & (FMASK), &fp, &fd)) {
656                   VN_RELE(vp);
657                   return error;
658               }
659           }
660           else {
661               osi_Panic("afs_syscall_iopen: bad fstype = %d\n",
662                         vfsp->vfs_fstype);
663           }
664         vfile_ready(fp, vp);
665         rvp->r_val1 = fd;
666         return 0;
667 }
668 #else
669 /* afs_syscall_iopen
670  * EFS/XFS version vectors to correct code based vfs_fstype. Expects a
671  * 64 bit inode number.
672  */
673 int
674 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t *rvp)
675 {
676         struct file *fp;
677         int fd;
678         int error;
679         struct vfs* vfsp;
680
681         AFS_STATCNT(afs_syscall_iopen);
682         if (!afs_suser())
683                 return EPERM;
684         vfsp = vfs_devsearch(dev);
685         if (!vfsp) {
686             return ENXIO;
687         }
688
689         if (vfsp->vfs_fstype == xfs_fstype) {
690             struct xfs_inode *xip;
691             struct vnode *vp;
692             if (error = xfs_igetinode(vfsp, (dev_t)dev, inode, &xip))
693                 return error;
694             vp = XFS_ITOV(xip);
695             if (error = falloc(vp, (usrmod+1) & (FMASK), &fp, &fd)) {
696                 VN_RELE(vp);
697                 return error;
698             }
699         }
700         else if (vfsp->vfs_fstype == efs_fstype) {
701             struct inode *ip;
702             if (error = igetinode(vfsp, (dev_t)dev, inode, &ip))
703                 return error;
704             if (error = falloc(EFS_ITOV(ip), (usrmod+1) & (FMASK), &fp, &fd)) {
705                 iput(ip);
706                 return error;
707             }
708             iunlock(ip);
709         }
710         else {
711             osi_Panic("afs_syscall_iopen: bad fstype = %d\n",
712                       vfsp->vfs_fstype);
713         }
714         fready(fp);
715         rvp->r_val1 = fd;
716         return 0;
717 }
718 #endif /* AFS_SGI65_ENV */
719
720 int
721 iopen(struct iopenargs *uap, rval_t *rvp)
722 {
723      AFS_STATCNT(iopen);
724      return (afs_syscall_iopen(uap->dev, (ino_t)uap->inode, uap->usrmod,
725                                rvp));
726 }
727
728 int
729 iopen64(struct iopenargs64 *uap, rval_t *rvp)
730 {
731      AFS_STATCNT(iopen);
732      return (afs_syscall_iopen(uap->dev,
733                                (ino_t)((uap->inode_hi<<32) | uap->inode_lo),
734                                uap->usrmod, rvp));
735 }
736
737 #else /* AFS_SGI_XFS_IOPS_ENV */
738 /* iopen/afs_syscall_iopen
739  *
740  * Original EFS only 32 bit iopen call.
741  */
742 int
743 iopen(struct iopenargs *uap, rval_t *rvp)
744 {
745      AFS_STATCNT(iopen);
746      return (afs_syscall_iopen(uap->dev, uap->inode, uap->usrmod, rvp));
747 }
748
749 int
750 afs_syscall_iopen(dev, inode, usrmod, rvp)
751 int dev, inode, usrmod;
752 rval_t *rvp;
753 {
754         struct file *fp;
755         struct inode *ip;
756         int fd;
757         int error;
758
759         AFS_STATCNT(afs_syscall_iopen);
760         if (!afs_suser())
761                 return EPERM;
762         if (error = igetinode(0, (dev_t)dev, inode, &ip))
763                 return error;
764         if (error = falloc(EFS_ITOV(ip), (usrmod+1) & (FMASK), &fp, &fd)) {
765                 iput(ip);
766                 return error;
767         }
768         iunlock(ip);
769         rvp->r_val1 = fd;
770 #ifdef  AFS_SGI53_ENV
771         fready(fp);
772 #endif
773         return 0;
774 }
775 #endif /* AFS_SGI_XFS_IOPS_ENV */
776
777 /*
778  * Support for iinc() and idec() system calls--increment or decrement
779  * count on inode.
780  * Restricted to super user.
781  * Only VICEMAGIC type inodes.
782  */
783 #ifdef AFS_SGI_XFS_IOPS_ENV
784 #ifdef AFS_SGI_EFS_IOPS_ENV
785 /* efs_iincdec
786  *
787  * XFS/EFS iinc/idec code for EFS. Uses 32 bit inode numbers. 
788  */
789 static int efs_iincdec(vfsp, inode, inode_p1, amount)
790 struct vfs *vfsp;
791 int inode, inode_p1, amount;
792 {
793     struct inode *ip;
794     int error;
795
796     if (error = igetinode(vfsp, NULL, inode, &ip))
797         return error;
798     
799     if (!IS_VICEMAGIC(ip))
800         error = EPERM;
801     else if (((struct afsparms *)ip->i_afs)->vicep1 != inode_p1)
802         error = ENXIO;
803     else {
804         ip->i_nlink += amount;
805         osi_Assert(ip->i_nlink >= 0);
806         if (ip->i_nlink == 0) {
807             CLEAR_VICEMAGIC(ip);
808             afsidestroy(ip);
809         }
810         ip->i_flags |= ICHG;
811     }
812     /* XXX sync write?? */
813     iput(ip);
814     return error;
815 }
816 #endif /* AFS_SGI_EFS_IOPS_ENV */
817
818 /* xfs_iincdec
819  *
820  * XFS/EFS iinc/idec code for EFS. Uses 64 bit inode numbers. 
821  */
822 static int xfs_iincdec64(struct vfs *vfsp, ino_t inode, int inode_p1,
823                          int amount)
824 {
825     vnode_t *vp;
826     xfs_inode_t *ip;
827     int code = 0;
828     afs_xfs_attr_t attrs;
829     int length = SIZEOF_XFS_ATTR_T;
830     afs_xfs_dattr_t dattr;
831     struct vattr vattr;
832     int nlink;
833     int vol;
834     
835     code = xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
836                     (void*)0, (xfs_ino_t)inode, XFS_ILOCK_SHARED, &ip, 
837                     (daddr_t)0);
838     if (code)
839         return code;
840
841     vp = XFS_ITOV(ip);
842     xfs_iunlock(ip, XFS_ILOCK_SHARED);
843     
844     vattr.va_mask = AT_GID | AT_UID | AT_MODE;
845     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
846     if (code) 
847         code = EPERM;
848
849     if (!code && (vattr.va_gid != XFS_VICEMAGIC))
850         code = EPERM;
851         
852     if (!code && (AFS_XFS_VNO_CLIP(inode_p1) != vattr.va_uid))
853         code = ENXIO;
854
855     if (code) {
856         VN_RELE(vp);
857         return code;
858     }
859
860     nlink = vattr.va_mode & AFS_XFS_MODE_LINK_MASK;
861     nlink += amount;
862     if (nlink > 07) {
863         code = EOVERFLOW;
864     }
865     if (nlink > 0) {
866         vattr.va_mode &= ~AFS_XFS_MODE_LINK_MASK;
867         vattr.va_mode |= nlink;
868         vattr.va_mask = AT_MODE;
869         AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
870         VN_RELE(vp);
871         return code;
872     }
873     else {
874         char path[64];
875         b64_string_t stmp1, stmp2;
876         vnode_t *dvp;
877         xfs_inode_t *ip;
878             
879         length = SIZEOF_XFS_ATTR_T;
880         AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char*)&attrs, &length,
881                                 ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
882         VN_RELE(vp);
883         if (!code) {
884             if (length != SIZEOF_XFS_ATTR_T
885                 || attrs.at_attr_version != AFS_XFS_ATTR_VERS)
886                 return EINVAL;
887         }
888         /* Get the vnode for the directory this file is in. */
889         if (!attrs.at_pino)
890             return ENOENT;
891
892         code = xfs_getinode(vp->v_vfsp, NULL, attrs.at_pino, &ip);
893         if (code)
894             return code;
895
896         dvp = XFS_ITOV(ip);
897         xfs_iunlock(ip, XFS_ILOCK_SHARED);
898
899         /* Verify directory attributes. */
900         length = SIZEOF_XFS_DATTR_T;
901         AFS_VOP_ATTR_GET(dvp, AFS_XFS_DATTR , (char*)&dattr, &length,
902                          ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
903         if (!code) {
904             if (length != SIZEOF_XFS_DATTR_T
905                 || dattr.atd_version != AFS_XFS_ATD_VERS)
906                 code = ENXIO;
907         }
908         if (code) {
909             VN_RELE(dvp);
910             return code;
911         }
912
913         strcpy(path, ".");
914         strcat(path, int_to_base64(stmp1, attrs.at_param[2]));
915         strcat(path, ".");
916         strcat(path, int_to_base64(stmp1, attrs.at_tag));
917             
918         AFS_VOP_REMOVE(dvp, path, OSI_GET_CURRENT_CRED(), code);
919                 
920         if (!code) {
921             int code2;
922             vattr.va_mask = AT_NLINK;
923             AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(),
924                             code2);
925             if (!code2) {
926                 if (vattr.va_nlink == 2) {
927                     vnode_t *ddvp; /* parent of volume directory. */
928                     /* Try to remove the directory if this is a volume
929                      * special file. It's ok to fail.
930                      */
931                     AFS_VOP_LOOKUP(dvp, "..", &ddvp,
932                                    (struct pathname *)NULL,
933                                    0, OSI_GET_CURRENT_RDIR(),
934                                    OSI_GET_CURRENT_CRED(), code2);
935                     if (!code2) {
936                         VN_RELE(dvp);
937                         dvp = (vnode_t*)0;
938                         strcpy(path, ".");
939                         if (attrs.at_name_version == AFS_XFS_NAME_VERS2)
940                             strcpy(path, AFS_INODE_DIR_NAME);
941                         else 
942                             strcpy(path, ".");
943                         int_to_base64(stmp1,
944                                       (attrs.at_param[1] == INODESPECIAL) ?
945                                       attrs.at_param[3] : attrs.at_param[0]);
946                         strcat(path, stmp1);
947                         AFS_LOCK_VOL_CREATE();
948                         AFS_VOP_RMDIR(ddvp, path, OSI_GET_CURRENT_CDIR(),
949                                       OSI_GET_CURRENT_CRED(), code2);
950                         AFS_UNLOCK_VOL_CREATE();
951                         VN_RELE(ddvp);
952                     }
953                 }
954             }
955         }
956         if (dvp)
957             VN_RELE(dvp);
958     }
959     return code;
960 }
961
962 int
963 iincdec64(int dev, int inode_hi, int inode_lo, int inode_p1, int amount)
964 {
965     struct vfs *vfsp;
966
967     if (!afs_suser())
968         return EPERM;
969 #ifdef AFS_SGI65_ENV
970     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
971 #else
972     vfsp = vfs_devsearch(dev);
973 #endif
974     if (!vfsp) {
975         return ENXIO;
976     }
977
978     if (vfsp->vfs_fstype == xfs_fstype) {
979         ino_t inode;
980         inode = inode_hi;
981         inode <<= 32;
982         inode |= inode_lo;
983         return xfs_iincdec64(vfsp, inode, inode_p1, amount);
984     }
985 #ifdef AFS_SGI_EFS_IOPS_ENV
986     else if (vfsp->vfs_fstype == efs_fstype) {
987         return efs_iincdec(vfsp, inode_lo, inode_p1, amount);
988     }
989 #endif /* AFS_SGI_EFS_IOPS_ENV */
990     return ENXIO;
991 }
992
993 int
994 afs_syscall_idec64(int dev, int inode_hi, int inode_lo, int inode_p1)
995 {
996     return iincdec64(dev, inode_hi, inode_lo, inode_p1, -1);
997 }
998
999 int
1000 afs_syscall_iinc64(int dev, int inode_hi, int inode_lo, int inode_p1)
1001 {
1002     return iincdec64(dev, inode_hi, inode_lo, inode_p1, 1);
1003 }
1004
1005
1006
1007
1008 struct iincargs {
1009         sysarg_t        dev;
1010         sysarg_t        inode;
1011         sysarg_t        inode_p1;
1012 };
1013
1014 #ifdef AFS_SGI65_ENV
1015 int iinc(struct iincargs *uap, rval_t *rvp) {
1016     AFS_STATCNT(iinc);
1017     return ENOTSUP;
1018 }
1019 int idec(struct iincargs *uap, rval_t *rvp) {
1020     AFS_STATCNT(idec);
1021     return ENOTSUP;
1022 }
1023 #else
1024 /* iincdec
1025  *
1026  * XFS/EFS iinc/idec entry points for EFS only fileservers.
1027  *
1028  */
1029 int
1030 iincdec(dev, inode, inode_p1, amount)
1031 int dev, inode, inode_p1, amount;
1032 {
1033     struct vfs *vfsp;
1034     
1035     if (!afs_suser())
1036         return EPERM;
1037     vfsp = vfs_devsearch(dev);
1038     if (!vfsp) {
1039         return ENXIO;
1040     }
1041     if (vfsp->vfs_fstype != efs_fstype)
1042         return ENOSYS;
1043
1044     return efs_iincdec(vfsp, inode, inode_p1, amount);
1045 }
1046 int
1047 iinc(struct iincargs *uap, rval_t *rvp) {
1048     AFS_STATCNT(iinc);
1049     return (iincdec(uap->dev, uap->inode, uap->inode_p1, 1));
1050 }
1051
1052 int
1053 idec(struct iincargs *uap, rval_t *rvp) {
1054     AFS_STATCNT(idec);
1055     return (iincdec(uap->dev, uap->inode, uap->inode_p1, -1));
1056 }
1057 #endif /* AFS_SGI65_ENV */
1058
1059 #else /* AFS_SGI_XFS_IOPS_ENV */
1060 /* afs_syscall_iincdec iinc idec
1061  *
1062  * These are the original EFS only entry points.
1063  */
1064 int
1065 afs_syscall_iincdec(dev, inode, inode_p1, amount)
1066 int dev, inode, inode_p1, amount;
1067 {
1068         struct inode *ip;
1069         int error = 0;
1070
1071         if (!afs_suser())
1072                 return EPERM;
1073         if (error = igetinode(0, (dev_t)dev, inode, &ip))
1074                 return error;
1075
1076         if (!IS_VICEMAGIC(ip))
1077             error = EPERM;
1078         else if (((struct afsparms *)ip->i_afs)->vicep1 != inode_p1)
1079             error = ENXIO;
1080         else {
1081                 ip->i_nlink += amount;
1082                 osi_Assert(ip->i_nlink >= 0);
1083                 if (ip->i_nlink == 0) {
1084                     CLEAR_VICEMAGIC(ip);
1085                     afsidestroy(ip);
1086                 }
1087                 ip->i_flags |= ICHG;
1088         }
1089         /* XXX sync write?? */
1090         iput(ip);
1091         return error;
1092 }
1093
1094 struct iincargs {
1095         sysarg_t        dev;
1096         sysarg_t        inode;
1097         sysarg_t        inode_p1;
1098 };
1099
1100 int
1101 iinc(struct iincargs *uap, rval_t *rvp) {
1102     AFS_STATCNT(iinc);
1103     return (afs_syscall_iincdec(uap->dev, uap->inode, uap->inode_p1, 1));
1104 }
1105
1106 int
1107 idec(struct iincargs *uap, rval_t *rvp) {
1108     AFS_STATCNT(idec);
1109     return (afs_syscall_iincdec(uap->dev, uap->inode, uap->inode_p1, -1));
1110 }
1111 #endif /* AFS_SGI_XFS_IOPS_ENV */
1112
1113 #ifdef AFS_SGI_XFS_IOPS_ENV
1114 /* afs_syscall_ilistinode64
1115  * Gathers up all required info for ListViceInodes in one system call.
1116  */
1117 int
1118 afs_syscall_ilistinode64(int dev, int inode_hi, int inode_lo,
1119                          int datap, int datalenp)
1120 {
1121     int code = 0;
1122     ino_t inode;
1123     xfs_inode_t *ip;
1124     vfs_t *vfsp;
1125     vnode_t *vp;
1126     struct vattr vattr;
1127     afs_xfs_attr_t attrs;
1128     int length;
1129     i_list_inode_t data;
1130     int idatalen;
1131
1132     if (!afs_suser())
1133         return EPERM;
1134 #ifdef AFS_SGI65_ENV
1135     vfsp = vfs_devsearch(dev, xfs_fstype);
1136 #else
1137     vfsp = vfs_devsearch(dev);
1138 #endif
1139     if (!vfsp) {
1140         return ENXIO;
1141     }
1142 #ifndef AFS_SGI65_ENV
1143     if (vfsp->vfs_fstype != xfs_fstype)
1144         return ENOSYS;
1145 #endif
1146
1147     AFS_COPYIN((char*)datalenp, &idatalen, sizeof(int), code);
1148     if (idatalen < sizeof(i_list_inode_t)) {
1149         idatalen = sizeof(i_list_inode_t);
1150         AFS_COPYOUT((char*)datalenp, (char*)&idatalen, sizeof(int), code);
1151         return E2BIG;
1152     }
1153     idatalen = sizeof(i_list_inode_t);
1154     AFS_COPYOUT((char*)datalenp, (char*)&idatalen, sizeof(int), code);
1155
1156     AFS_COPYIN((char*)datap, (char*)&data, sizeof(i_list_inode_t), code);
1157     if (data.ili_version != AFS_XFS_ILI_VERSION) {
1158         data.ili_version = AFS_XFS_ILI_VERSION;
1159         AFS_COPYOUT((char*)&data, (char*)datap, sizeof(i_list_inode_t), code);
1160         return EINVAL;
1161     }
1162     
1163     
1164     inode = inode_hi;
1165     inode <<= 32;
1166     inode |= inode_lo;
1167     code = xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)), 
1168                     (void*)0, (xfs_ino_t)inode,
1169                     XFS_ILOCK_SHARED, &ip, (daddr_t)0);
1170     if (code)
1171         return code;
1172     
1173     vp = XFS_ITOV(ip);
1174     xfs_iunlock(ip, XFS_ILOCK_SHARED);
1175     
1176     length = SIZEOF_XFS_ATTR_T;
1177
1178     AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char*)&attrs, &length,
1179                             ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
1180     if (code) { 
1181         code = EPERM;
1182     }
1183
1184     if (!code) {
1185         if (attrs.at_attr_version != AFS_XFS_ATTR_VERS)
1186             code = EINVAL;
1187     }
1188     
1189     if (!code) {
1190         vattr.va_mask = AT_STAT;
1191         AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
1192     }
1193     
1194     if (!code) {
1195         bzero((char*)&data, sizeof(data));
1196         data.ili_info.inodeNumber = inode;
1197         data.ili_info.byteCount = vattr.va_size;
1198         data.ili_info.linkCount = (vattr.va_mode & AFS_XFS_MODE_LINK_MASK);
1199         bcopy((char*)attrs.at_param, (char*)data.ili_info.param,
1200               sizeof(data.ili_info.param));
1201         data.ili_attr_version = attrs.at_attr_version;
1202         data.ili_name_version = attrs.at_name_version;
1203         data.ili_tag = attrs.at_tag;
1204         data.ili_pino = attrs.at_pino;
1205         data.ili_vno = vattr.va_uid;
1206         data.ili_magic = vattr.va_gid;
1207         AFS_COPYOUT((char*)&data, (char*)datap, sizeof(data), code);
1208     }
1209     VN_RELE(vp);
1210     return code;
1211 }
1212 #endif /* AFS_SGI_XFS_IOPS_ENV */