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