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