diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 1999-04-30 01:59:18 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 1999-04-30 01:59:18 +0000 |
commit | 07b4a33ad356d7a2d300f6ca586637879e4ad5fd (patch) | |
tree | 9ea7e04a0d6f54ee8c45d6d897eb401f906e5032 /usr.sbin | |
parent | b0d7a6a83d7eaa1e9a526c576527d81957b28268 (diff) |
Import of arla-0.35.7
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/afs/src/arlad/darla.c | 104 | ||||
-rw-r--r-- | usr.sbin/afs/src/arlad/darla.h | 51 | ||||
-rw-r--r-- | usr.sbin/afs/src/arlad/discon.h | 339 | ||||
-rw-r--r-- | usr.sbin/afs/src/arlad/discon_log.c | 480 | ||||
-rw-r--r-- | usr.sbin/afs/src/arlad/discon_log.h | 268 | ||||
-rw-r--r-- | usr.sbin/afs/src/arlad/fs_errors.h | 92 | ||||
-rw-r--r-- | usr.sbin/afs/src/arlad/reconnect.c | 2172 | ||||
-rw-r--r-- | usr.sbin/afs/src/arlad/reconnect.h | 39 | ||||
-rw-r--r-- | usr.sbin/afs/src/lib/ko/vlmisc.c | 92 | ||||
-rw-r--r-- | usr.sbin/afs/src/lwp/plwp.c | 939 | ||||
-rw-r--r-- | usr.sbin/afs/src/lwp/plwp.h | 191 | ||||
-rw-r--r-- | usr.sbin/afs/src/lwp/process-vpp.s | 171 | ||||
-rw-r--r-- | usr.sbin/afs/src/lwp/rw.c | 255 | ||||
-rw-r--r-- | usr.sbin/afs/src/rx/rx-new.h | 239 | ||||
-rw-r--r-- | usr.sbin/afs/src/rx/rxgencon.h | 39 | ||||
-rw-r--r-- | usr.sbin/afs/src/rxdef/rx_pkt.xg | 77 | ||||
-rw-r--r-- | usr.sbin/afs/src/util/heap.c | 295 | ||||
-rw-r--r-- | usr.sbin/afs/src/util/heap.h | 91 | ||||
-rw-r--r-- | usr.sbin/afs/src/util/heaptest.c | 120 |
19 files changed, 6054 insertions, 0 deletions
diff --git a/usr.sbin/afs/src/arlad/darla.c b/usr.sbin/afs/src/arlad/darla.c new file mode 100644 index 00000000000..886d2e5eba0 --- /dev/null +++ b/usr.sbin/afs/src/arlad/darla.c @@ -0,0 +1,104 @@ +/* $OpenBSD: darla.c,v 1.1 1999/04/30 01:59:07 art Exp $ */ +/* COPYRIGHT (C) 1998 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS + * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS + * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF + * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY + * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE + * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE + * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE + * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY + * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST + * ALSO BE INCLUDED. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#include "arla_local.h" + +RCSID("$KTH: darla.c,v 1.5 1998/12/21 21:54:03 assar Exp $"); + +int DARLA_Open(DARLA_file *Dfp, char *fname, int oflag) +{ + + int fd; + + fd = open(fname, oflag); + arla_log(ADEBMISC, "DARLA_Open: errno=%d\n", errno); + if (fd > 0) + { + Dfp->fd = fd; + Dfp->offset=0; + Dfp->log_entries = 0; + } + + return fd; +} + +int DARLA_Close(DARLA_file *Dfp) +{ + int ret; + + ret = close(Dfp->fd); + Dfp->fd = 0; + Dfp->offset =0; + arla_log(ADEBMISC, "DARLA_Close: ret=%d\n", ret); + return ret; +} + +int DARLA_Read(DARLA_file *Dfp, char *cp, int len) +{ + ssize_t read_size; + + if (Dfp->fd) + { + read_size = read (Dfp->fd, cp, len); + } + else + read_size = 0; + + return read_size; +} + +int DARLA_Write(DARLA_file *Dfp, char *cp, int len) +{ + ssize_t write_size; + + if (Dfp->fd) + { + write_size = write(Dfp->fd, cp, len); + } + else + write_size = 0; + + return write_size; +} + +int DARLA_Seek(DARLA_file *Dfp, int offset, int whence) +{ + + off_t lseek_off; + + if (Dfp->fd) + { + lseek_off = lseek(Dfp->fd, offset, whence); + } + else + lseek_off = 0; + + return lseek_off; +} diff --git a/usr.sbin/afs/src/arlad/darla.h b/usr.sbin/afs/src/arlad/darla.h new file mode 100644 index 00000000000..80853a8c174 --- /dev/null +++ b/usr.sbin/afs/src/arlad/darla.h @@ -0,0 +1,51 @@ +/* $OpenBSD: darla.h,v 1.1 1999/04/30 01:59:07 art Exp $ */ +/* COPYRIGHT (C) 1998 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS + * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS + * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF + * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY + * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE + * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE + * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE + * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY + * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST + * ALSO BE INCLUDED. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +/* $KTH: darla.h,v 1.3 1998/12/21 21:54:03 assar Exp $ */ + +#ifndef _DARLA_H +#define _DARLA_H + +#include <lock.h> + +typedef struct _DARLA_file { + int fd; /*file descriptor of the current file */ + long offset; /*current byte offset */ + struct Lock bs_lock; /*lock to synchronize access */ + long log_entries; /*number of entries */ +} DARLA_file; + +int DARLA_Open(DARLA_file *Dfp, char *fname, int oflag); +int DARLA_Close(DARLA_file *Dfp); +int DARLA_Read(DARLA_file *Dfp, char *cp, int len); +int DARLA_Write(DARLA_file *Dfp, char *cp, int len); +int DARLA_Seek(DARLA_file *Dfp, int offset, int whence); + +#endif /* _DARLA_H */ diff --git a/usr.sbin/afs/src/arlad/discon.h b/usr.sbin/afs/src/arlad/discon.h new file mode 100644 index 00000000000..0d87b28474e --- /dev/null +++ b/usr.sbin/afs/src/arlad/discon.h @@ -0,0 +1,339 @@ +/* $OpenBSD: discon.h,v 1.1 1999/04/30 01:59:07 art Exp $ */ +/* COPYRIGHT (C) 1998 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS + * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS + * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF + * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY + * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE + * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE + * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE + * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY + * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST + * ALSO BE INCLUDED. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +/* +** These are defines for the different type of disconnected +** operations stored in the log. +*/ + +#ifndef _DISCONNH +#define _DISCONNH + + +/* these are define for integrity checking */ +#define CHECK_SLOTS (long) 0x1 +#define CHECK_LRUQ (long) 0x2 +#define CHECK_FREEVS (long) 0x4 + +/* values for the dflags in the vcache */ +#define VC_DIRTY 0x01 +#define KEEP_VC 0x04 +#define DBAD_VC 0x08 /* This is a know bad vcache */ +/* this flags is used by GetVSlot to mark when a vcache was read from +** the disk. +*/ +#define READ_DISK 0x10 + +/* Flags for dflags in the fcache */ +#define KEEP_DC 0x01 + +/* Flags in the afs_VindexFlags */ + +#define VC_FREE 0x01 +#define HAS_CCORE 0x02 +/* 0x04 is used by KEEP_VC */ +#define VC_DATAMOD 0x08 +#define VC_FLAG 0x10 +#define VC_CLEARAXS 0x20 +#define VC_HAVECB 0x40 + +/* magic number for data files */ + +#define AFS_DHMAGIC 0x7635fac1 + +/* these are the file name extensions for various errors */ +#define STORE_EXT ".store" +#define RENAME_EXT ".ren" +#define CREATE_EXT ".creat" +#define MKDIR_EXT ".mkdir" +#define LINK_EXT ".link" +#define SYMLINK_EXT ".slink" +#define ORPH_EXT ".orph" + +/* conflicting defs with arla_local.h */ +/*enum discon_modes { + CONNECTED, + DISCONNECTED, + FETCH_ONLY, + PARTIALLY_CONNECTED +};*/ + +#define IS_DISCONNECTED(state) (state == DISCONNECTED) +#define IS_FETCHONLY(state) (state == FETCH_ONLY) +#define IS_PARTIAL(state) (state == PARTIALLY_CONNECTED) +#define IS_CONNECTED(state) (state == CONNECTED) +#define LOG_OPERATIONS(state) ((state == DISCONNECTED) || \ + (state == FETCH_ONLY) || (state == PARTIALLY_CONNECTED)) +#define USE_OPTIMISTIC(state) ((state == DISCONNECTED) || \ + (state == FETCH_ONLY)) + + +/* These are the different levels of error logging */ +#define DISCON_ERR 0 +#define DISCON_NOTICE 1 +#define DISCON_INFO 2 +#define DISCON_DEBUG 3 + +/* pioctl flags */ +#define AFS_DIS_RECON 0 /* normal reconnect */ +#define AFS_DIS_DISCON 1 /* disconnect */ +#define AFS_DIS_PANIC 2 /* die, monster devil, die */ +#define AFS_DIS_RECONTOSS 3 /* reconnect now! */ +#define AFS_DIS_QUERY 4 /* query disconnected state */ +#define AFS_DIS_FETCHONLY 5 /* disconnect, fetch-only mode */ +#define AFS_DIS_PARTIAL 6 /* partially connected mode */ +#define AFS_DIS_DISCONTOSS 7 /* disconnect without discarding callbacks */ + + +/* these are items defined to fhe PSetDOps */ + +typedef enum { GET_BACKUP_LOG_NAME, + SET_USERLOG_LEVEL, + SET_FILELOG_LEVEL, + SET_LOGFILE, + UPDATE_FLAGS, + PING_SERVER, + GET_LOG_NAME, + GIVEUP_CBS, + PRINT_INFO, + VERIFY_VCACHE, + VERIFY_DCACHE } dis_setopt_op_t; + +#if 0 +#define MAX_NAME 255 +#endif + +typedef struct dis_setop_info { + dis_setopt_op_t op; + char data[MAX_NAME]; +} dis_setop_info_t; + + +#ifdef KERNEL + + +#define CELL_DIRTY 0x01 +#define REALLY_BIG 1024 + +struct save_cell { + long cell; /* unique id assigned by venus */ + char cellName[MAX_NAME]; /* char string name of cell */ + short cellHosts[MAXHOSTS]; /* volume *location* hosts for this cell */ + short lcell; /* Associated linked cell */ + short states; /* state flags */ + long fsport; /* file server port */ + long vlport; /* volume server port */ + short cellIndex; /* relative index number per cell */ + short dindex; /* disconnected index */ +}; + +#define SERV_DIRTY 0x01 + +struct save_server { + unsigned int cell; /* cell in which this host resides */ + long host; /* in network byte order, except subsys */ + long portal; /* in network byte order */ + unsigned int random; /* server priority, used for randomizing requests */ + char isDown; /* result of decision if server is down. */ + char vcbCount; /* count of vcbs */ + short dindex; /* disconnected index */ +}; + + +#define VOL_DIRTY 0x01 + +struct save_volume { + long cell; /* the cell in which the volume resides */ + long volume; /* This volume's ID number. */ + char name[MAX_NAME]; /* This volume's name, or 0 if unknown */ + short serverHost[MAXHOSTS]; /* servers serving this volume */ + struct VenusFid dotdot; /* dir to access as .. */ + struct VenusFid mtpoint; /* The mount point for this volume. */ + long rootVnode, rootUnique; /* Volume's root fid */ + long roVol; + long backVol; + long rwVol; /* For r/o vols, original read/write volume. */ + long accessTime; /* last time we used it */ + long copyDate; /* copyDate field, for tracking vol releases */ + char states; /* snuck here for alignment reasons */ + short dindex; +}; + + +#define LLIST_SIZE 1024 + + +#ifndef GET_WRITE +#define GET_WRITE 0x1 +#define GET_READ 0x2 +#define GET_SHARED 0x4 + +#define REL_WRITE 0x10 +#define REL_READ 0x20 +#define REL_SHARED 0x40 + +#define S_TO_W 0x100 +#define W_TO_S 0x200 +#define W_TO_R 0x400 +#define S_TO_R 0x800 +#endif /* GET_WRITE */ + +struct llist { + struct afs_lock *lk; + short operation; + short who; + struct llist * next; + struct llist *prev; +}; + +/* These are definition for the translation flags fields */ + +#define KNOWNBAD 0x20 +#define SYMLINK 0x40 +struct name_trans { + struct VenusFid pfid; + int ntrans_idx; + int oname_idx; + int nname_idx; + int next_nt_idx; + char *old_name; + char *new_name; + struct name_trans *next; +}; + +struct translations { + struct VenusFid oldfid; + struct VenusFid newfid; + u_long flags; + hyper validDV; + int trans_idx; + long callback; + long cbExpires; + int nl_idx; + struct translations *next; + struct name_trans *name_list; +}; + + + +/* + * this struct is used to help speed up finding the number of callbacks for + * each server + */ + +struct serv_cbcount { + long server; + long count; + struct serv_cbcount *next; +}; + +/* Stuff for the link name persistence */ + +#define MAP_ENTS 100 +#define NAME_UNIT 255 +#define NAME_DIRTY 0x1 + +/* header for the name backing file */ +typedef struct map_header { + long magic; /* magic number */ + int num_ents; /* number of names stored */ + char flags; /* flags for in core copy */ +} map_header_t; + +/* commented out */ +/* + * this struct holds all the information pertaining to a certain + * backing store used to keep persistance information + */ +/*typedef struct backing_store { + long bs_inode; + struct osi_dev bs_dev; + char *bs_name; + map_header_t *bs_header; + char *bs_map; + struct afs_lock bs_lock; + struct osi_file *tfile; +} backing_store_t;*/ + +#endif /* KERNEL */ + +/* CacheItems file has a header of type struct afs_fheader (keep aligned properly) */ +struct afs_dheader { + long magic; + long firstCSize; + long otherCSize; + long spare; + long current_op; + enum connected_mode mode; +}; + +#ifdef KERNEL + +#define have_shared_lock(lock) \ + ((((lock)->excl_locked==SHARED_LOCK) && \ + ((lock)->proc == osi_curpid())) ? 1 : 0) + +#define have_write_lock(lock) \ + ((((lock)->excl_locked==WRITE_LOCK) && \ + ((lock)->proc == osi_curpid())) ? 1 : 0) + +extern struct llist *llist; +extern struct llist *cur_llist; + +/* these are function declarations so I can compile with -Wall in gcc, + * not really needed, but help make clean compiles. + */ + +extern int strlen(); +#ifndef AFS_NETBSD_ENV +extern void strcpy(); +#endif /* AFS_NETBSD_ENV */ +extern void bcopy(); +extern int dir_Delete(); +extern int dir_FindBlobs(); +extern int dir_Lookup(); +extern int dir_Create(); +extern int find_file_name(); +extern int afs_create(); +extern int afs_PutDCache(); + +#endif /* KERNEL */ + +#endif /* _DISCONNH */ + + +#ifdef DISCONN +typedef struct _fid_cb { +VenusFid fid; +struct _fid_cb *next; +} fid_cb; +#endif + + diff --git a/usr.sbin/afs/src/arlad/discon_log.c b/usr.sbin/afs/src/arlad/discon_log.c new file mode 100644 index 00000000000..b895067a6d4 --- /dev/null +++ b/usr.sbin/afs/src/arlad/discon_log.c @@ -0,0 +1,480 @@ +/* $OpenBSD: discon_log.c,v 1.1 1999/04/30 01:59:07 art Exp $ */ +/* COPYRIGHT (C) 1998 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS + * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS + * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF + * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY + * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE + * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE + * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE + * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY + * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST + * ALSO BE INCLUDED. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +/* + * This file contains functions that relate to performance statistics + * for disconnected operation. + */ + +#include "arla_local.h" + +RCSID("$KTH: discon_log.c,v 1.8 1998/12/21 21:54:03 assar Exp $"); + +extern int dlog_mod; +extern long current_op_no; + +extern DARLA_file log_data; + +extern long Log_is_open; + +log_ent_t log_head; + +int DARLA_Open(DARLA_file *Dfp, char *fname, int oflag); +int DARLA_Read(DARLA_file *Dfp, char *cp, int len); +int DARLA_Write(DARLA_file *Dfp, char *cp, int len); +int DARLA_Seek(DARLA_file *Dfp, int offset, int whence); + +/* + * read an entry from the log file described by tfile. The result is + * put into the log_ent data. This return 0 if successful, 1 if + * it failed to some reason ( ie. no more data ). + */ + +int +read_log_ent(DARLA_file * tfile, log_ent_t *in_log) +{ + int len; + char *bp; + + if (DARLA_Read(tfile, (char *) in_log, sizeof (int)) != sizeof(int)) + return 1; + + len = in_log->log_len - sizeof(int); + bp = (char *) in_log + sizeof(int); + + if (DARLA_Read(tfile, bp, len) != len) { + printf("read_log_ent: short read \n"); + return 1; + } + return 0; +} + +#if 0 +void +update_log_ent(offset, flags) +long offset; +int flags; +{ + struct DARLA_file *tfile; + log_ent_t *log_ent; + int code; + + tfile = DARLA_UFSOpen(&log_data.bs_dev, log_data.bs_inode); + if (!tfile) + panic("update_log_ent: failed to open log file"); + + DARLA_Seek(tfile, offset); + + log_ent = (log_ent_t *) malloc(sizeof(log_ent_t)); + code = read_log_ent(tfile, log_ent); + + if (code) { + printf("update_log_ent: failed to read log entry at %d \n", + offset); + } else { + + /* set the log flags */ + log_ent->log_flags |= flags; + + /* write the entry back out */ + DARLA_Seek(tfile, offset); + DARLA_Write(tfile, (char *) log_ent, log_ent->log_len); + } + free(log_ent); + DARLA_Close(tfile); +} +#endif + + +/* write the log entries to disk */ +long +write_log_ent(int len, log_ent_t *log) +{ + + long new_num; + static int index=0; + + arla_warnx (ADEBDISCONN,"We are writing a log"); + if (!Log_is_open) { + return -1; + } + + if (log_head.next == 0) { + log_head.next = (log_ent_t *) malloc(sizeof(log_ent_t)); + *log_head.next = *log; + log_head.next->next = 0; + } + else { + log->next = log_head.next; + log_head.next = (log_ent_t *) malloc(sizeof(log_ent_t)); + *log_head.next = *log; + } + + ObtainWriteLock(&log_data.bs_lock); + + new_num = 0; + + log->log_opno = new_num; + gettimeofday(&log->log_time, 0); + + log->log_offset = log_data.offset; + log->log_flags = 0; + log->log_index = index++; + + DARLA_Write(&log_data, (char *) log, len); + + ReleaseWriteLock(&log_data.bs_lock); + + return (new_num); +} + +long +log_dis_store(struct vcache *avc) +{ + log_ent_t *store; + long op_no; + + store = (log_ent_t *) malloc(sizeof(log_ent_t)); + + store->log_op = DIS_STORE; + store->st_fid = avc->fid; + store->st_origdv = avc->DataVersion; + store->st_flag = avc->flag; + + /* have to log cred as well */ + store->cred = avc->cred; + + /* figure out the length of a store entry */ + store->log_len = ((char *) &(store->st_origdv)) - ((char *) store) + + sizeof(store->st_origdv); + + op_no = write_log_ent(store->log_len, store); + + free(store); + return op_no; +} + + +/* Log a mkdir operation */ +long +log_dis_mkdir(struct vcache *pvc, struct vcache *dvc, + AFSStoreStatus *attrs, char *name) +{ + log_ent_t *mkdir; + long op_no; + + mkdir = (log_ent_t *) malloc(sizeof(log_ent_t)); + + mkdir->log_op = DIS_MKDIR; + mkdir->md_dirfid = dvc->fid; + /*Ba Wu: the data vers. for child dir*/ + mkdir->md_dversion = dvc->DataVersion; + mkdir->md_parentfid = pvc->fid; + mkdir->cred = pvc->cred; + mkdir->md_vattr = *attrs; + + /* save the name */ + strcpy((char *) mkdir->md_name, name); + + /* calculate the length of this record */ + mkdir->log_len = ((char *) mkdir->md_name - (char *) mkdir) + + strlen(name) + 1; + + op_no = write_log_ent(mkdir->log_len, mkdir); + + free(mkdir); + return op_no; +} + + +long +log_dis_create(struct vcache *parent, struct vcache *child, char *name) +{ + log_ent_t *create; + long op_no; + struct vcache *ch; + struct vcache *par; + + ch = child; + par = parent; + ch->DataVersion = child->DataVersion; + + create = (log_ent_t *) malloc(sizeof(log_ent_t)); + + create->log_op = DIS_CREATE; + create->cr_filefid = ch->fid; + create->cr_parentfid = par->fid; + create->cr_origdv = ch->DataVersion; + create->cred = parent->cred; + + strcpy((char *) create->cr_name, name); + + create->log_len = ((char *) create->cr_name - (char *) create) + + strlen(name) + 1; + + op_no = write_log_ent(create->log_len, create); + + free(create); + return op_no; +} + +long +log_dis_remove(struct vcache *avc, FCacheEntry *childentry, char *name) +{ + log_ent_t *remove; + long op_no; + remove = (log_ent_t *) malloc(sizeof(log_ent_t)); + + remove->log_op = DIS_REMOVE; + remove->cred = avc->cred; + remove->rm_filefid = avc->fid; + remove->rm_origdv = avc->DataVersion; + remove->rm_chentry = childentry; + + strcpy((char *) remove->rm_name, name); + + remove->log_len = ((char *) remove->rm_name - (char *) remove) + + strlen(name) + 1; + + op_no = write_log_ent(remove->log_len, remove); + + free(remove); + arla_log(ADEBDISCONN, "remove: fid.Cell=%ld, fid.fid.Volume=%ld, " + "fid.Unique=%ld", \ + remove->rm_filefid.Cell, + remove->rm_filefid.fid.Volume, + remove->rm_filefid.fid.Unique); + + return op_no; +} + + +long +log_dis_rmdir(struct vcache *dir, FCacheEntry *cce, const char *name) +{ + log_ent_t *rmdir; + long op_no; + + rmdir = malloc(sizeof(log_ent_t)); + + rmdir->log_op = DIS_RMDIR; + rmdir->cred = dir->cred; + rmdir->rd_parentfid = dir->fid; + rmdir->rd_direntry = cce; + + strcpy((char *) rmdir->rd_name, name); + + rmdir->log_len = ((char *) rmdir->rd_name - (char *) rmdir) + + strlen(name) + 1; + + op_no = write_log_ent(rmdir->log_len, rmdir); + + free(rmdir); + return op_no; +} + + +long +log_dis_rename(struct vcache *old_dir, char *old_name, + struct vcache *new_dir, char *new_name) +{ + log_ent_t *rename; + char *cp; + + rename = malloc(sizeof(log_ent_t)); + + rename->log_op = DIS_RENAME; + rename->rn_oparentfid = old_dir->fid; + rename->rn_nparentfid = new_dir->fid; + rename->rn_origdv = old_dir->DataVersion; + rename->rn_overdv = new_dir->DataVersion; + rename->cred = old_dir->cred; + + strcpy((char *) rename->rn_names, old_name); + cp = (char *) rename->rn_names + strlen(old_name) + 1; + + strcpy((char *) cp, new_name); + cp += strlen(new_name) + 1; + + rename->log_len = (char *) cp - (char *) rename; + + write_log_ent(rename->log_len, rename); + + free(rename); + return 0; +} + + + +/* Log a link operation */ +long +log_dis_link(struct vcache *pvc, struct vcache *lvc, char *name) + +{ + log_ent_t *link; + long op_no; + + link = malloc(sizeof(log_ent_t)); + + link->log_op = DIS_LINK; + link->cred = pvc->cred; + link->ln_linkfid = lvc->fid; + link->ln_parentfid = pvc->fid; + + /* save the name */ + strcpy((char *) link->ln_name, name); + /* calculate the length of this record */ + link->log_len = ((char *) link->ln_name - (char *) link) + + strlen(name) + 1; + + op_no = write_log_ent(link->log_len, link); + + free(link); + return op_no; +} + +/* Log a symlink operation */ +long +log_dis_symlink(struct vcache *pvc, struct vcache *cvc, + AFSStoreStatus *attr, char *linkname, char *content) +{ + log_ent_t *slink; + long op_no; + + slink = malloc(sizeof(log_ent_t)); + + slink->log_op = DIS_SYMLINK; + slink->sy_parentfid = pvc->fid; + slink->sy_filefid = cvc->fid; + slink->sy_attr = *attr; + slink->cred = pvc->cred; + + /* copy in the link name */ + strcpy((char *) slink->sy_name, linkname); + strcpy((char *) slink->sy_content, content); + + /* calculate the length of this record */ + slink->log_len = ( (char *) slink->sy_content - + (char *) slink) + + strlen(content) + 1; + + op_no = write_log_ent(slink->log_len, slink); + + free(slink); + return op_no; +} + + +/* Log a setattr operation */ +long +log_dis_setattr(struct vcache *tvc, struct xfs_attr *attrs) +{ + log_ent_t *setattr; + long op_no; + + setattr = (log_ent_t *) malloc(sizeof(log_ent_t)); + + setattr->log_op = DIS_SETATTR; + setattr->sa_fid = tvc->fid; + setattr->cred = tvc->cred; + setattr->sa_origdv = tvc->DataVersion; + + setattr->sa_vattr = *attrs; + + /* calculate the length of this record */ + setattr->log_len = ((char *) &setattr->sa_origdv - (char *) setattr) + + sizeof(setattr->sa_origdv); + + op_no = write_log_ent(setattr->log_len, setattr); + + arla_log(ADEBDISCONN, "log_dis_setattr: fid.Cell=0x%x, fid.fid.Volume=0x%x," + "fid.fid.Vnode=0x%x, fid.fid.Unique=0x%x", + tvc->fid.Cell, + tvc->fid.fid.Volume, + tvc->fid.fid.Vnode, + tvc->fid.fid.Unique); + + arla_log(ADEBDISCONN, "log_dis_setattr: writing %d byte log entry."); + + free(setattr); + return op_no; +} + +long +log_dis_nonmutating(struct vcache *tvc, log_ops_t op) +{ +#ifdef LOGNONMUTE + log_ent_t *non_mute; + long op_no; + + non_mute = (log_ent_t *) malloc(sizeof(log_ent_t)); + + non_mute->log_op = op; + non_mute->cred = tvc->cred; + non_mute->nm_fid = tvc->fid; + non_mute->nm_origdv = tvc->DataVersion; + non_mute->log_len = ((char *) &non_mute->nm_origdv - + (char *) non_mute) + sizeof(non_mute->nm_origdv); + + /* XXX lhuston removed for debugging */ + op_no = write_log_ent(non_mute->log_len, non_mute); + + free(non_mute); + return op_no; +#else + return 0; /* 0 was current_op_no */ +#endif +} + + +long +log_dis_access(struct vcache *tvc) +{ + return log_dis_nonmutating(tvc, DIS_ACCESS); +} + +long +log_dis_readdir(struct vcache *tvc) +{ + return log_dis_nonmutating(tvc, DIS_READDIR); +} + +long +log_dis_readlink(struct vcache *tvc) +{ + return log_dis_nonmutating(tvc, DIS_READLINK); +} + +long +log_dis_fsync(struct vcache *tvc) +{ + /* treat an fsync as a store */ + return log_dis_nonmutating(tvc, DIS_FSYNC); +} diff --git a/usr.sbin/afs/src/arlad/discon_log.h b/usr.sbin/afs/src/arlad/discon_log.h new file mode 100644 index 00000000000..2fdb2a6ef94 --- /dev/null +++ b/usr.sbin/afs/src/arlad/discon_log.h @@ -0,0 +1,268 @@ +/* $OpenBSD: discon_log.h,v 1.1 1999/04/30 01:59:07 art Exp $ */ +/* COPYRIGHT (C) 1998 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS + * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS + * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF + * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY + * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE + * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE + * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE + * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY + * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST + * ALSO BE INCLUDED. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +/* + * This file contains all the relevant information pertaining to logging + * for disconnected afs. + */ +/* replace vattr with xfs_attr in the log */ +#include <xfs/xfs_attr.h> +#ifndef _DISCONN_LOG_H + +#define _DISCONN_LOG_H + +#define BUFSIZE 256 + +#define MAX_NAME AFSNAMEMAX + +enum log_ops { + DIS_STORE, + DIS_MKDIR, + DIS_CREATE, + DIS_REMOVE, + DIS_RMDIR, + DIS_RENAME, + DIS_LINK, + DIS_SYMLINK, + DIS_SETATTR, + DIS_FSYNC, + DIS_ACCESS, + DIS_READDIR, + DIS_READLINK, + DIS_INFO, + DIS_START_OPT, + DIS_END_OPT, + DIS_REPLAYED +}; + +typedef enum log_ops log_ops_t; + +/* These are defines for the different log flags that can be set */ +#define LOG_INACTIVE 0x1 /* log no longer needs replay */ +#define LOG_REPLAYED 0x2 /* log entry was replayed */ +#define LOG_OPTIMIZED 0x4 /* log entry was optimized away */ +#define LOG_GENERATED 0x8 /* log entry created by optimizer */ + + +/* defines to make access easier */ +#define st_fid log_data.st.fid +#define st_origdv log_data.st.origdv + +/* added flag option */ +#define st_flag log_data.st.flag + +typedef u_int32_t hyper; + +/* a really stripped down version of CITI's vcache */ +struct vcache { + u_int32_t DataVersion; + struct VenusFid fid; + xfs_cred cred; + u_int flag; /* write flag */ +}; + +typedef struct store_log_data { + struct VenusFid fid; /* fid of the file */ + u_int flag; /* write flag */ + hyper origdv; /* cached data version of file */ +} store_log_data_t; + +/* defines to make access easier */ +#define md_dirfid log_data.md.dirfid +#define md_parentfid log_data.md.parentfid +#define md_vattr log_data.md.vattr +#define md_dversion log_data.md.dversion +#define md_name log_data.md.name + +typedef struct mkdir_log_data { + struct VenusFid dirfid; /* Fid of this dir */ + struct VenusFid parentfid; /* Fid of parent */ + /* struct vattr vattr; attrs to create with */ + AFSStoreStatus vattr; /* log store_status */ /*Ba Wu */ + hyper dversion; /* cached data version of file */ + char name[MAX_NAME]; /* space to store create name */ +} mkdir_log_data_t; + + +/* defines to make access easier */ +#define cr_filefid log_data.cr.filefid +#define cr_parentfid log_data.cr.parentfid +#define cr_vattr log_data.cr.vattr +#define cr_mode log_data.cr.mode +#define cr_exists log_data.cr.exists +#define cr_excl log_data.cr.excl +#define cr_origdv log_data.cr.origdv +#define cr_name log_data.cr.name + +typedef struct create_log_data { + struct VenusFid filefid; /* Fid of this file */ + struct VenusFid parentfid; /* Fid of parent */ + struct xfs_attr vattr; /* attrs to create with */ + int mode; /* mode to create with */ + int exists; /* did file exists */ + int excl; /* is file create exclusive ? */ + hyper origdv; /* cached data version of file */ + char name[MAX_NAME]; /* space to store create name */ +} create_log_data_t; + + + + +/* defines to make access easier */ +#define rm_filefid log_data.rm.filefid +#define rm_chentry log_data.rm.chentry +#define rm_origdv log_data.rm.origdv +#define rm_name log_data.rm.name + +typedef struct remove_log_data { + struct VenusFid filefid; /* Fid of this file */ + /*struct VenusFid parentfid;*/ /* Fid of parent */ + FCacheEntry *chentry; /*The entry for the deleted file*/ + hyper origdv; /* cached data version of file */ + char name[MAX_NAME]; /* space to store remove name */ +} remove_log_data_t; + + + +/* defines to make access easier */ +#define rd_direntry log_data.rd.direntry +#define rd_parentfid log_data.rd.parentfid +#define rd_name log_data.rd.name + +typedef struct rmdir_log_data { + FCacheEntry *direntry; /*Entry of this dir */ + struct VenusFid parentfid; /* Fid of parent */ + char name[MAX_NAME]; /* space to store dir name */ +} rmdir_log_data_t; + + +/* defines to make access easier */ +#define rn_oparentfid log_data.rn.oparentfid +#define rn_nparentfid log_data.rn.nparentfid +#define rn_renamefid log_data.rn.renamefid +#define rn_overfid log_data.rn.overfid +#define rn_origdv log_data.rn.origdv +#define rn_overdv log_data.rn.overdv +#define rn_names log_data.rn.names + +typedef struct rename_log_data { + struct VenusFid oparentfid; /* Fid of parent */ + struct VenusFid nparentfid; /* Fid of parent */ + struct VenusFid renamefid; /* Fid of file being rename */ + struct VenusFid overfid; /* Fid of overwritten file */ + hyper origdv; /* cached data version of file */ + hyper overdv; /* overwritten version of cached data */ + char names[MAX_NAME * 2]; /* space to store dir name */ +} rename_log_data_t; + +/* defines to make access easier */ +#define ln_linkfid log_data.ln.linkfid +#define ln_parentfid log_data.ln.parentfid +#define ln_name log_data.ln.name + +typedef struct link_log_data { + struct VenusFid linkfid; /* Fid of this dir */ + struct VenusFid parentfid; /* Fid of parent */ + char name[MAX_NAME]; /* space to store create name */ +} link_log_data_t; + +/* defines to make access easier */ +#define sy_linkfid log_data.sy.linkfid +#define sy_parentfid log_data.sy.parentfid +#define sy_filefid log_data.sy.filefid +#define sy_attr log_data.sy.attr +#define sy_name log_data.sy.name +#define sy_content log_data.sy.content + + +typedef struct slink_log_data { + struct VenusFid linkfid; /* Fid of this link */ + struct VenusFid parentfid; /* Fid of parent */ + struct VenusFid filefid; /* Fid of file */ + AFSStoreStatus attr; /* attrs to create with */ + char name[MAX_NAME]; /* space to name */ + char content[MAX_NAME]; /* space to new name */ +} slink_log_data_t; + +/* defines to make access easier */ +#define sa_fid log_data.sa.fid +#define sa_vattr log_data.sa.vattr +#define sa_origdv log_data.sa.origdv + +typedef struct setattr_log_data { + struct VenusFid fid; /* operand fid */ + struct xfs_attr vattr; /* attrs to set */ + hyper origdv; /* cached data version number */ +} setattr_log_data_t; + + +/* defines to make access easier */ +#define nm_fid log_data.nm.fid +#define nm_origdv log_data.nm.origdv + +typedef struct nonmute_log_data { + struct VenusFid fid; /* fid */ + hyper origdv; /* cached data version */ +} nonmute_log_data_t; + + + +typedef struct log_ent { + int log_len; /* len of this entry */ + log_ops_t log_op; /* operation */ + long log_opno; /* operation number */ + struct timeval log_time; /* time operation was logged */ + long log_offset; /* offset into the log file */ + short log_flags; /* offset into the log file */ + uid_t log_uid; /* uid of person performing op */ + xfs_cred cred; /* user credential */ + int log_index; /* index for the log */ + struct log_ent *next; /* point to the next one */ + + union { + store_log_data_t st; + mkdir_log_data_t md; + create_log_data_t cr; + remove_log_data_t rm; + rmdir_log_data_t rd; + rename_log_data_t rn; + link_log_data_t ln; + slink_log_data_t sy; + setattr_log_data_t sa; + nonmute_log_data_t nm; + } log_data; +} log_ent_t; + + +long log_dis_create(struct vcache *parent, struct vcache *child, char *name); + + +#endif /* _DISCONN_LOG_H */ + diff --git a/usr.sbin/afs/src/arlad/fs_errors.h b/usr.sbin/afs/src/arlad/fs_errors.h new file mode 100644 index 00000000000..8a4695d4416 --- /dev/null +++ b/usr.sbin/afs/src/arlad/fs_errors.h @@ -0,0 +1,92 @@ +/* $OpenBSD: fs_errors.h,v 1.1 1999/04/30 01:59:08 art Exp $ */ +/* + * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _FS_ERRORS_H_ +#define _FS_ERRORS_H_ 1 + +#define VICE_SPECIAL_ERRORS 101 + +#define VICE_SPECIAL_ERRORS_MIN 101 +#define VICE_SPECIAL_ERRORS_MAX 112 + +#define VSALVAGE 101 +#define VNOVNODE 102 +#define VNOVOL 103 +#define VVOLEXISTS 104 +#define VNOSERVICE 105 +#define VOFFLINE 106 +#define VONLINE 107 +#define VDISKFULL 108 +#define VOVERQUOTA 109 +#define VBUSY 110 +#define VMOVED 111 +#define VIO 112 + +#define VRESTARTING -100 + +#define ARLA_SPECIAL_ERROR_ADD 4000 +#define ARLA_SPECIAL2_ERROR_ADD 4600 + +#define ARLA_VSALVAGE (ARLA_SPECIAL_ERROR_ADD+VSALVAGE) +#define ARLA_VNOVNODE (ARLA_SPECIAL_ERROR_ADD+VNOVNODE) +#define ARLA_VNOVOL (ARLA_SPECIAL_ERROR_ADD+VNOVOL) +#define ARLA_VVOLEXISTS (ARLA_SPECIAL_ERROR_ADD+VVOLEXISTS) +#define ARLA_VNOSERVICE (ARLA_SPECIAL_ERROR_ADD+VNOSERVICE) +#define ARLA_VOFFLINE (ARLA_SPECIAL_ERROR_ADD+VOFFLINE) +#define ARLA_VONLINE (ARLA_SPECIAL_ERROR_ADD+VONLINE) +#define ARLA_VDISKFULL (ARLA_SPECIAL_ERROR_ADD+VDISKFULL) +#define ARLA_VOVERQUOTA (ARLA_SPECIAL_ERROR_ADD+VOVERQUOTA) +#define ARLA_VBUSY (ARLA_SPECIAL_ERROR_ADD+VBUSY) +#define ARLA_VMOVED (ARLA_SPECIAL_ERROR_ADD+VMOVED) +#define ARLA_VIO (ARLA_SPECIAL_ERROR_ADD+VIO) +#define ARLA_VRESTARTING (ARLA_SPECIAL2_ERROR_ADD+VRESTARTING) + +static inline int __attribute__ ((unused)) +conv_to_arla_errno(int error) +{ + if (error >= VICE_SPECIAL_ERRORS_MIN && + error <= VICE_SPECIAL_ERRORS_MAX) + return error + ARLA_SPECIAL_ERROR_ADD; + else if (error == VRESTARTING) + return ARLA_VRESTARTING; + else + return error; +} + +#endif /* _FS_ERRORS_H_ */ diff --git a/usr.sbin/afs/src/arlad/reconnect.c b/usr.sbin/afs/src/arlad/reconnect.c new file mode 100644 index 00000000000..bebb4b82e41 --- /dev/null +++ b/usr.sbin/afs/src/arlad/reconnect.c @@ -0,0 +1,2172 @@ +/* $OpenBSD: reconnect.c,v 1.1 1999/04/30 01:59:10 art Exp $ */ +/* COPYRIGHT (C) 1998 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS + * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS + * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF + * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY + * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE + * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE + * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE + * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY + * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST + * ALSO BE INCLUDED. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +/* + * Do merging of the files that changed with we was in disconnected mode + */ + +#include "arla_local.h" + +RCSID("$KTH: reconnect.c,v 1.11 1999/02/15 04:49:43 art Exp $"); + +static int reconnect_nonmute(struct vcache *, int, struct timeval); +static int reconnect_putattr(struct vcache *, struct xfs_attr *); +static int reconnect_putdata(struct vcache *); +static int reconnect_remove(struct vcache *, FCacheEntry *childentry, char *); +static int reconnect_rename(struct vcache *, struct vcache *, char *, char *); +static int reconnect_rmdir(struct vcache *vcp, FCacheEntry *childEntry, + char *name); +static int reconnect_mkdir(struct vcache *parent, struct vcache *curdir, + AFSStoreStatus *store_status, char *name); +static int reconnect_link(struct vcache *parent, struct vcache *existing, + char *name); +static int reconnect_symlink(struct vcache *parent, struct vcache *child, + AFSStoreStatus *store_attr, char *name, + char *contents); +static int reconnect_create(struct vcache *parent, struct vcache *child, + char *name); +static int reconnect_mut_chk(FCacheEntry *fce, CredCacheEntry *ce, + int version); + +static int check_log_todo(log_ent_t * , VenusFid *, VenusFid *); +static int is_done_before(int no); +static void add_done_list(int no); +static void clear_log_entry(void); +static void clear_index_list(void); + +typedef struct _fid_trans{ + VenusFid logged_fid; + VenusFid fetched_fid; + struct _fid_trans *next, *prev; +} fid_trans; + +typedef struct _fid_keep{ + char name[MAX_NAME]; + AFSFid kept_fid; + struct _fid_keep *next; +} fid_keep; + +typedef struct _index_list{ + int index; + struct _index_list * next; +} index_list; + +fid_trans *fid_AD_head, *fid_AD_tail; +fid_keep *fid_KP_head; +index_list * index_head; +extern log_ent_t log_head; + + +/* + * + */ + +static void +set_fid_value(VenusFid *new, VenusFid *old) +{ + if(old==0) { + new->fid.Volume = 0; + new->fid.Vnode = 0; + new->fid.Unique = 0; + } else { + new->fid.Volume = old->fid.Volume; + new->fid.Vnode = old->fid.Vnode; + new->fid.Unique = old->fid.Unique; + } +} + +/* + * + */ + +void +do_replay(char *log_file, int log_entries, VenusFid *changed_fid) +{ + int fd, len, i; + log_ent_t *cur_log; + struct vcache vc, vc_new; + char *name, *name_new; + fid_trans *fid_tmp; + fid_keep * fid_KP_tail; + VenusFid new_fid; + + int count=1; /* Used to record how may actions we have done*/ + + fid_AD_tail = fid_AD_head; + cur_log = (log_ent_t *) malloc(sizeof(log_ent_t)); + fd = open(log_file, O_RDONLY | O_BINARY); + + set_fid_value(&new_fid , 0); + + while (read(fd, cur_log, sizeof(int))){ + + if (cur_log->log_len < sizeof(*cur_log) - sizeof(cur_log->log_data) || + cur_log->log_len > sizeof(log_ent_t)) { + arla_log(ADEBDISCONN, "do_replay: corrupt log entry, log_len %d", + cur_log->log_len); + goto terminate; + } + + len = cur_log->log_len - sizeof(int); + + if (!read(fd, ((char *)cur_log + sizeof(int)), len)){ + arla_log(ADEBDISCONN, "do_replay: read bad log entry..."); + goto terminate; + } + + arla_log(ADEBDISCONN, + "do_replay: read %d bytes of log entry.", + cur_log->log_len); + + if (is_done_before(cur_log->log_index)==1) + continue; /* the log entry has been executed */ + else { + if (changed_fid !=0) { + int is_log_todo = 0; + + is_log_todo = check_log_todo(cur_log, changed_fid, &new_fid); + if (is_log_todo ==0) + continue; /* This log should not be executed */ + } + } + + add_done_list(cur_log->log_index); + + /* big case/switch statement to switch log_op */ + switch (cur_log->log_op){ + + case DIS_STORE: + vc.fid = cur_log->st_fid; + vc.DataVersion = cur_log->st_origdv-1; + vc.flag = cur_log->st_flag; + vc.cred = cur_log->cred; + arla_log(ADEBDISCONN, + "%d action is to do_replay: **replay** (putdata) op...", + count++); + reconnect_putdata(&vc); + break; + case DIS_SETATTR: + vc.fid = cur_log->sa_fid; + vc.DataVersion = cur_log->sa_origdv; + vc.flag = 0; + vc.cred = cur_log->cred; + arla_log(ADEBDISCONN, + "%d action is to do_replay: **replay** (putattr) op...", + count++); + reconnect_putattr(&vc, &(cur_log->sa_vattr)); + break; + case DIS_REMOVE: { + FCacheEntry *childentry; + vc.fid = cur_log->rm_filefid; + vc.DataVersion = cur_log->rm_origdv; + vc.flag = 0; + vc.cred = cur_log->cred; + childentry = cur_log->rm_chentry; + name = cur_log->rm_name; + arla_log(ADEBDISCONN, + "%d action is to do_replay: **replay** " + "(file remove) op...", + count++); + reconnect_remove(&vc, childentry, name); + break; + } + case DIS_RMDIR: { + FCacheEntry *child; + vc.fid = cur_log->rd_parentfid; + name = cur_log->rd_name; + vc.cred = cur_log->cred; + child = cur_log->rd_direntry; + arla_log (ADEBDISCONN, + "%d action is to do_replay: **rmdir** " + "(directory remove) op...", + count++); + reconnect_rmdir(&vc, child, name); + break; + } + case DIS_RENAME: + vc.fid = cur_log->rn_oparentfid; + vc.DataVersion = cur_log->rn_origdv; + vc.flag = 0; + vc.cred = cur_log->cred; + vc_new.fid = cur_log->rn_nparentfid; + vc_new.DataVersion = cur_log->rn_overdv; + vc_new.flag = 0; + vc_new.cred = cur_log->cred; + name = cur_log->rn_names; + for (i=0; *(name+i)!='\0';++i); + name_new = name+i+1; + arla_log(ADEBDISCONN, + "%d action is to do_replay: **replay** (rename) op...", + count++); + reconnect_rename(&vc, &vc_new, name, name_new); + break; + case DIS_MKDIR: { + AFSStoreStatus store_status; + vc.fid = cur_log->md_parentfid; + vc.cred = cur_log->cred; + store_status = cur_log->md_vattr; + vc_new.fid = cur_log->md_dirfid; + /*Ba Wu: child's data vers*/ + vc_new.DataVersion = cur_log->md_dversion; + name = cur_log->md_name; + arla_log(ADEBDISCONN, + "%d action is to DO_Replay: **replay** (mkdir) op...", + count++); + reconnect_mkdir(&vc, &vc_new, &store_status, name); + break; + } + case DIS_LINK: + vc.cred = cur_log->cred; + vc.fid = cur_log->ln_parentfid; + vc_new.fid = cur_log->ln_linkfid; + name = cur_log->ln_name; + arla_log(ADEBDISCONN, + "%d action is to do_replay: **replay** (link) op...", + count++); + reconnect_link(&vc, &vc_new, name); + break; + case DIS_SYMLINK: { + char *new_name; + AFSStoreStatus store_attr; + + vc.fid = cur_log->sy_parentfid; + vc.cred = cur_log->cred; + name = cur_log->sy_name; + new_name = cur_log->sy_content; + vc_new.fid = cur_log->sy_filefid; + store_attr = cur_log->sy_attr; + arla_log(ADEBDISCONN, + "%d action is to do_replay: **replay** (symlink) op...", + count++); + reconnect_symlink(&vc, &vc_new, &store_attr, name, new_name); + break; + } + case DIS_CREATE: + vc.fid = cur_log->cr_parentfid; + vc.cred = cur_log->cred; + + vc_new.fid = cur_log->cr_filefid; + vc_new.DataVersion = cur_log->cr_origdv; + arla_log(ADEBDISCONN, + "%d action is to DO_Replay: **replay** (create) op...", + count++); + name = cur_log->cr_name; + reconnect_create(&vc, &vc_new, name); + break; + case DIS_ACCESS: + vc.fid = cur_log->nm_fid; + vc.DataVersion = cur_log->nm_origdv; + vc.cred = cur_log->cred; + arla_log(ADEBDISCONN, + "%d action is to do_replay: **replay** (nonmutating) op", + count++); + reconnect_nonmute(&vc, cur_log->log_op, cur_log->log_time); + break; + + default: + arla_log(ADEBDISCONN, + "%d action is to do_replay: skipping the current op=%d", + count++,cur_log->log_op); + } + } + + if (changed_fid ==0) { + clear_index_list(); /* clean all index when after discon */ + clear_log_entry(); + /* clean up, remove all associative data structures */ + fid_AD_tail = fid_AD_head; + while(fid_AD_tail) + { + fid_tmp = fid_AD_tail->next; + free(fid_AD_tail); + fid_AD_tail = fid_tmp; + } + /* SWW Qiyue 28: We need to reset head to 0*/ + fid_AD_head = 0; + fid_KP_tail = fid_KP_head; + while(fid_KP_tail) + { + fid_keep *fid_tmp; + + fid_tmp = fid_KP_tail->next; + free(fid_KP_tail); + fid_KP_tail = fid_tmp; + } + + fid_KP_head = 0; + } + terminate: + + arla_warnx (ADEBDISCONN,"We have done total %d replays",count-1); + close(fd); + free(cur_log); + return; +} + +/* + * + */ + +static int +check_rm_fid (VenusFid v1, VenusFid v2) +{ + if(v1.fid.Vnode == v2.fid.Vnode && + v1.fid.Volume == v2.fid.Volume && + v1.fid.Unique == v2.fid.Unique ) + return 1; + else + return 0; +} + +/* + * + */ + +static int +check_log_fid(struct vcache vc, VenusFid *fid) +{ + log_ent_t *temp = log_head.next; + + if (vc.fid.fid.Vnode == fid->fid.Vnode && + vc.fid.fid.Volume == fid->fid.Volume && + vc.fid.fid.Unique == fid->fid.Unique) + return 1; + + while (temp!=0) { + switch(temp->log_op) { + case DIS_RENAME: + if (check_rm_fid(temp->rn_oparentfid,*fid)==1) + return 1; + default: + temp = temp->next; + break; + } + } + return 0; +} + +/* + * + */ + +static int +check_log_todo(log_ent_t * cur_log , VenusFid *fid, VenusFid *newfid) +{ + VenusFid *lookfid; + struct vcache vc, vc_new; + int will_do = 0; + + if (newfid->fid.Vnode ==0 && + newfid->fid.Volume == 0 && + newfid->fid.Unique ==0) + lookfid = fid; + else + lookfid = newfid; /* For create and putdata */ + + switch (cur_log->log_op){ + case DIS_STORE: + vc.fid = cur_log->st_fid; + will_do = check_log_fid(vc, lookfid); + if (will_do==1) { + set_fid_value(newfid, 0); + return 1; + } + break; + case DIS_SETATTR: + vc.fid = cur_log->sa_fid; + will_do = check_log_fid(vc, lookfid); + if (will_do==1) { + set_fid_value(newfid , &cur_log->sa_fid); + return 1; + } + break; + case DIS_REMOVE: + vc.fid = cur_log->rm_filefid; + will_do = check_log_fid(vc, lookfid); + if (will_do==1) { + return 1; + } + break; + case DIS_RMDIR: + vc.fid = cur_log->rd_parentfid; + will_do = check_log_fid(vc, lookfid); + if (will_do==1) { + return 1; + } + break; + case DIS_RENAME: + vc.fid = cur_log->rn_oparentfid; + will_do = check_log_fid(vc, lookfid); + if (will_do==1) { + return 1; + } + vc_new.fid = cur_log->rn_nparentfid; + will_do = check_log_fid(vc_new, lookfid); + if (will_do==1) { + return 1; + } + break; + case DIS_MKDIR: + vc.fid = cur_log->md_parentfid; + will_do = check_log_fid(vc, lookfid); + if (will_do==1) { + return 1; + } + break; + case DIS_LINK: + break; + case DIS_SYMLINK: + will_do = check_log_fid(vc, lookfid); + if (will_do==1) { + return 1; + } + break; + case DIS_CREATE: + vc.fid = cur_log->cr_parentfid; + will_do = check_log_fid(vc, lookfid); + if (will_do==1) { + set_fid_value(newfid , &cur_log->cr_filefid); + return 1; + } + break; + case DIS_FSYNC: + case DIS_ACCESS: + case DIS_READDIR: + case DIS_READLINK: + case DIS_INFO: + case DIS_START_OPT: + case DIS_END_OPT: + case DIS_REPLAYED: + /* A no op */ + break; + } + return 0; +} + + +#if 0 + +/* + * + */ + +void +keepfid_newrename(char *name, + AFSFid fid) +{ + if (fid_KP_head == 0) { + fid_KP_head = (fid_keep *)malloc(sizeof(fid_keep)); + assert(fid_KP_head); + + strcpy(fid_KP_head->name, name); + fid_KP_head->kept_fid = fid; + fid_KP_head->next = 0; + } + else { + fid_keep *temp; + + temp = (fid_keep *)malloc(sizeof(fid_keep)); + assert(temp); + + strcpy(temp->name, name); + temp->name[strlen(name)] = '\0'; + temp->kept_fid = fid; + temp->next = fid_KP_head->next; + fid_KP_head->next = temp; + } +} + +#endif + +/* + * + */ + +static int +find_venus (char *name, VenusFid *fid) +{ + fid_keep *fid_temp; + + if(fid_KP_head == 0 ) + return 1; /*error */ + + fid_temp = fid_KP_head; + + while(fid_temp) { + if (strcmp(fid_temp->name,name) == 0) { + fid->fid.Volume = fid_temp->kept_fid.Volume; + fid->fid.Vnode = fid_temp->kept_fid.Vnode; + fid->fid.Unique = fid_temp->kept_fid.Unique; + return 0; + } + fid_temp = fid_temp->next; + } + arla_warnx (ADEBDISCONN, "find_venus: *PANIC* not found fid for %s", name); + return 1; +} + + +/* + * + */ + +static VenusFid * +fid_translate(VenusFid *fid_in) +{ + fid_trans *fid_tmp; + VenusFid *fid_ret; + + if (!fid_AD_head) + return fid_in; + + fid_tmp = fid_AD_head; + + while(fid_tmp){ + + fid_ret=&fid_tmp->logged_fid; + + if ((fid_ret->Cell == fid_in->Cell) && + (fid_ret->fid.Volume == fid_in->fid.Volume) && + (fid_ret->fid.Vnode == fid_in->fid.Vnode) && + (fid_ret->fid.Unique == fid_in->fid.Unique)) + return &fid_tmp->fetched_fid; + + fid_tmp = fid_tmp->next; + } + return fid_in; +} + +/* + * + */ + +static void +clear_index_list(void) +{ + index_list *temp=index_head; + + while(temp!=0) { + index_list *tmp; + + tmp = temp->next; + free(temp); + temp = tmp; + } + index_head = 0; +} + +/* + * + */ + +static void +clear_log_entry(void) +{ + log_ent_t *temp=log_head.next; + + while(temp!=0) { + log_ent_t *tmp; + + tmp = temp->next; + free(temp); + temp = tmp; + } + log_head.next = 0; +} + +/* + * + */ + +static int +is_done_before(int no) +{ + index_list * temp = index_head; + + while(temp !=0) { + if (temp->index == no) + return 1; + else + temp = temp->next; + } + return 0; +} + +/* + * + */ + +static void +add_done_list(int no) +{ + if (!index_head) { + index_head = (index_list *)malloc(sizeof(index_list)); + assert(index_head); + index_head->index = no; + index_head->next = 0; + } else { + index_list * temp; + temp = (index_list *) malloc(sizeof(index_list)); + assert(temp); + temp->next = index_head->next; + index_head->next = temp; + temp->index = no; + } +} + +/* + * + */ + +static void +alloc_fid_trans(VenusFid *logged_fid) +{ + if (!fid_AD_head) + { + /*SWW Qiyue 28 Make sure we have the memory*/ + fid_AD_head = (fid_trans *) malloc(sizeof(fid_trans)); + assert(fid_AD_head); + + fid_AD_head->prev=fid_AD_head->next = 0; + fid_AD_tail = fid_AD_head; + fid_AD_tail->logged_fid = *logged_fid; + + } else{ + + /*SWW Qiyue 28 Make sure we have the memory*/ + fid_AD_tail->next = (fid_trans *) malloc(sizeof(fid_trans)); + assert(fid_AD_tail->next); + + fid_AD_tail->next->prev = fid_AD_tail; + fid_AD_tail->next->next = 0; + fid_AD_tail = fid_AD_tail->next; /*Ba ba: move tail ahead */ + fid_AD_tail->logged_fid = *logged_fid; + } +} + +/* + * + */ + +static void +fill_fid_trans (VenusFid *fetched_fid) +{ + fid_AD_tail->fetched_fid = *fetched_fid; +} + +/* + * + */ + +#if 0 +void +update_entry_flag (FCacheEntry *entry) +{ + entry->flags.attrp = FALSE; + entry->flags.datap = FALSE; +} +#endif + +/* + * + */ + +int reconnect_nonmute(struct vcache *vcp, int op, struct timeval log_time) +{ + FCacheEntry *fce, fce_fetched; + CredCacheEntry *ce; + int error; + VenusFid *fid; +#if 0 + ConnCacheEntry *conn; +#endif + + arla_warnx (ADEBDISCONN, + "Start of reconnect_nonmute by sww"); /*SWW Qiyue 25*/ + + fid = &(vcp->fid); + if (fid->Cell == -1) /* newly created file, skip reconnect */ + return 0; + + error = fcache_find(&fce, *fid); + /* assert(fce); */ + if (error) /* nonmute op on nonexisting data */ + { + arla_log(ADEBDISCONN, + "reconnect: nonmute op %d performed on cache " + "entry no longer exist locally!", + op); + return -1; + } + + arla_log(ADEBDISCONN, + "reconnect: DISCONNECTED nonmute " + "on fid.Cell=0x%x, fid.fid.Volume= 0x%x, fid.fid.Vnode=0x%x, " + "fid.fid.Unique=0x%x", fid->Cell, + fid->fid.Volume, + fid->fid.Vnode, + fid->fid.Unique); + + ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY); + assert (ce != NULL); + error = 0; + + /* setting some stuff so do_read_attr would work */ + fce->flags.attrp = TRUE; + fce->callback.CallBackType = 2; + fce_fetched = *fce; + /*conn = findconn (fce, ce);*/ + + error = read_attr(&fce_fetched, ce); + + arla_log(ADEBDISCONN, + "reconnect: logged DataVersion=%d, " + "fetched DataVersion=%d", + vcp->DataVersion, + fce_fetched.status.DataVersion); + + if (vcp->DataVersion < fce_fetched.status.DataVersion) + { + if (log_time.tv_usec >= fce_fetched.status.ServerModTime) + arla_log(ADEBDISCONN, + "Warning: nonmutating operation %d read stale data!", + op); + else if (log_time.tv_usec <= fce_fetched.status.ServerModTime && + (vcp->DataVersion +1) == fce_fetched.status.DataVersion) + arla_log(ADEBDISCONN, + "Notice: file modified once after nonmutating " + "operation %d.", + op); + else + arla_log(ADEBDISCONN, + "Warning: nonmutating operation %d might have read " + "stale data!", op); + } + + ReleaseWriteLock(&fce->lock); + cred_free(ce); + /*conn_free(conn);*/ + + return error; +} + +/* + * + */ + +int reconnect_remove(struct vcache *vcp, FCacheEntry *childentry, char *name) +{ + FCacheEntry *fce; + CredCacheEntry *ce; + int error; + VenusFid *fid, tempfid; /* Ba san: to check the deletion of file*/ + Result res; + int isupdate; + + ConnCacheEntry *conn; + fs_server_context context; + AFSFetchStatus status; + AFSVolSync volsync; + char tmp[5]; + xfs_cache_handle cache_handle; + + fid = &(vcp->fid); /* points to the VenusFid structure */ + fid = fid_translate(fid); + + arla_log(ADEBDISCONN, "reconnect: DISCONNECTED remove on " + "fid.Cell=0x%x, fid.fid. Volume= 0x%x, fid.fid.Vnode=0x%x, " + "fid.fid.Unique=0x%x", + fid->Cell, fid->fid.Volume, fid->fid.Vnode, fid->fid.Unique); + + /* ObtainWriteLock called in fcache_find */ + error = fcache_find(&fce, *fid); + assert (error == 0); + + ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY); + assert (ce != NULL); + + if (connected_mode != CONNMODE_PARCONNECTED) { + ObtainWriteLock(&childentry->lock); + isupdate = reconnect_mut_chk(childentry, ce, + childentry->status.DataVersion); + ReleaseWriteLock(&childentry->lock); + + if (isupdate) + { + xfs_cache_handle cache_handle; + + arla_log(ADEBDISCONN, + "reconnect_remove: can't remove because file modified!"); + cred_free(ce); + adir_creat (fce, name, childentry->fid.fid); + childentry->flags.attrp = FALSE; + ReleaseWriteLock(&fce->lock); + conv_dir (fce, ce, 0, &cache_handle, tmp, sizeof(tmp)); + ReleaseWriteLock(&fce->lock); + return -1; + } + } /* Ba ershi: we dont need to do it in parconn */ + + res.res = 0; + + assert (CheckLock(&fce->lock) == -1); + + conn = find_first_fs (fce, ce, &context); + +/* Ba san: check the file exists + + ReleaseWriteLock(&fce->lock); + error = adir_lookup(fce->fid, name, &tempfid, ce); + assert (error == 0); + ObtainWriteLock(&fce->lock); */ + + res.res = RXAFS_RemoveFile (conn->connection, + &fce->fid.fid, + name, + &status, + &volsync); + if (res.res) { + arla_log (ADEBDISCONN, "Could not RemoveFile: %s (%d)", + koerr_gettext(res.res), res.res); + goto out; + } + + arla_warnx (ADEBDISCONN,"In reconnect_remove: Remove the file %s",name); + +/* Ba san: Chcek the deletion of the file */ + ReleaseWriteLock(&fce->lock); + error = adir_lookup(fce->fid, name, &tempfid, ce); + ObtainWriteLock(&fce->lock); + + if (error == 0) { + int result; + + arla_warnx (ADEBDISCONN, + "In reconnect_remove: file %s needs to be deleted", + name); + result = adir_remove (fce,name); + assert ( result == 0); + } /* This is for the file produced during disconnect mode, + if error==ENOENT then the file is created during connect mode*/ + + + fce->status = status; + fce->volsync = volsync; + childentry->host = 0; /* Ba shiliu dont get callback */ + + volcache_update_volsync (fce->volume, fce->volsync); + conv_dir (fce, ce, 0, &cache_handle, tmp, sizeof(tmp)); + + out: + + cred_free(ce); + free_fs_server_context(&context); + ReleaseWriteLock(&fce->lock); + return error; +} + +/* + * + */ + +int +reconnect_rmdir(struct vcache *vcp, FCacheEntry *childEntry, char *name) +{ + FCacheEntry *fce; + CredCacheEntry *ce; + int error; + VenusFid *fid, tempfid; /* Ba san: to check the deletion of file*/ + Result res; + char tmp[5]; + int ret = 0; + Result tempres; + xfs_cache_handle cache_handle; + + ConnCacheEntry *conn; + fs_server_context context; + AFSFetchStatus status; + AFSVolSync volsync; + + fid = &(vcp->fid); /* points to the VenusFid structure */ + fid = fid_translate(fid); + + ret = fcache_find(&fce, *fid); + assert (ret == 0); + + ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY); + assert (ce != NULL); + + assert (CheckLock(&fce->lock) == -1); + + conn = find_first_fs (fce, ce, &context); + + ret = RXAFS_RemoveDir (conn->connection, + &fce->fid.fid, + name, + &status, + &volsync); + if (ret) { + arla_log (ADEBDISCONN, + "Could not RemoveDir : %s (%d)", + koerr_gettext(res.res),res.res); + goto out; + } + +/* Ba san: Chcek the deletion of the file */ + ReleaseWriteLock(&fce->lock); + error = adir_lookup(fce->fid, name, &tempfid, ce); + ObtainWriteLock(&fce->lock); + + if (error == 0) { + int result; + + arla_warnx (ADEBDISCONN, + "In reconnect_rmdir: file %s needs to be deleted",name); + result = adir_remove (fce,name); + assert ( result == 0); + } /* This is for the file produced during disconnect mode, + if error==ENOENT then the file is created during connect mode*/ + + fce->status = status; + fce->volsync = volsync; + + volcache_update_volsync (fce->volume, fce->volsync); + + tempres = conv_dir(fce, ce, 0, &cache_handle, tmp, sizeof(tmp)); + + childEntry->host = 0; /*Ba shiqi: no callback for this entry*/ + + out: + + cred_free(ce); + free_fs_server_context(&context); + ReleaseWriteLock(&fce->lock); + return error; +} + +/* + * + */ + +static int +reconnect_mut_chk(FCacheEntry *fce, CredCacheEntry *ce, int version) +{ + ConnCacheEntry *conn; + fs_server_context context; + FCacheEntry fetched = *fce; + int ret; + + AFSFetchStatus status; + AFSCallBack callback; + AFSVolSync volsync; + + assert (CheckLock (&fetched.lock) == -1); + +/*SWW Aug 01: >= is changed into > */ + conn = find_first_fs (&fetched, ce, &context); + + ret = RXAFS_FetchStatus (conn->connection, + &fce->fid.fid, + &status, + &callback, + &volsync); + if (ret) { + if (ret == -1) + ret = ENETDOWN; + free_fs_server_context(&context); + arla_warn (ADEBFCACHE, ret, "fetch-status"); + return ret; + } + + if (status.DataVersion > version) + { + arla_log(ADEBDISCONN, "reconnect_mut_chk: concurrent writes detected!"); + return 1; + } + free_fs_server_context(&context); + return 0; +} + +/* + * + */ + +void fcache_backfile_name(char *name, size_t len) +{ + static int no = 1; + + snprintf (name, len, "%04X",no++); + strcat (name, "bak"); + name[strlen(name)+1] = '\0'; +} + +/* + * + */ + +void +copy_cached_file(int from, int to) +{ + char tmpname[5],name_from[21],name_to[27]; + int fd_from, n, fd_to; + char buf[BUFSIZE]; + + strcpy(name_from,ARLACACHEDIR); + strcpy(name_to,ARLACACHEDIR); + sprintf(tmpname,"%04X",from); + strcat(name_from, tmpname); + sprintf(tmpname,"%04X",to); + strcat(name_to, tmpname); + fd_from = open(name_from,O_RDONLY | O_BINARY); + fd_to = open(name_to, O_WRONLY | O_CREAT | O_BINARY); + + while((n = read(fd_from, buf, BUFSIZE)) > 0) + write(fd_to, buf, n); + +#if 0 + if(fstat(fd_to, &statinfo)<0) { + arla_warnx(ADEBDISCONN,"ERROR"); + } +#endif + + close(fd_from); + close(fd_to); +} + +/* + * + */ + +int +reconnect_mut_newfile(FCacheEntry **fcep, pag_t cred,VenusFid *new_fid) +{ + + FCacheEntry *parent_fce; + u_long host; + char name[9],tmp[5]; + AFSStoreStatus store_attr; + AFSFetchStatus fetch_attr; + CredCacheEntry *ce; + AccessEntry *ae; + VenusFid newfid; + int ret; + int from, to; + xfs_cache_handle cache_handle; + + ret = fcache_find (&parent_fce, (*fcep)->parent); + assert (ret == 0); + + host = (*fcep)->host; + + ce = cred_get((*fcep)->parent.Cell, cred, CRED_ANY); + + fcache_backfile_name (name, sizeof(name)); + + store_attr.Mask = 8; + store_attr.ClientModTime = 430144; + store_attr.Owner = 1957724; + store_attr.Group = 21516; + store_attr.UnixModeBits = 420; + store_attr.SegSize = 0; + + create_file(parent_fce, name, &store_attr, &newfid, &fetch_attr, ce); + + (*fcep)->flags.datap = FALSE; /* Ba shiqi: we need to get the old from FS*/ + *new_fid = newfid; + from = (*fcep)->index; + ret = fcache_find(fcep, newfid); + assert (ret == 0); + to = (*fcep)->index; + (*fcep)->host = host; + (*fcep)->flags.attrp = TRUE; + (*fcep)->flags.datap = TRUE; + findaccess(ce->cred, (*fcep)->acccache, &ae); /*Ba shijiu obtain access */ + ae->cred = ce->cred; + ae->access = (*fcep)->status.CallerAccess; + + ReleaseWriteLock(&(*fcep)->lock); + + copy_cached_file(from, to); + ret = adir_creat (parent_fce, name, newfid.fid); + assert (ret ==0); + conv_dir (parent_fce, ce, 0, &cache_handle, tmp, sizeof(tmp)); + ReleaseWriteLock(&parent_fce->lock); + + return 0; +} + + +/* + * + */ + +int reconnect_putattr(struct vcache *vcp, struct xfs_attr *xap) +{ + + ConnCacheEntry *conn; + fs_server_context context; + struct rx_call *call; + VenusFid *fid; + CredCacheEntry *ce; + FCacheEntry *fce, *tempce; + AFSFetchStatus status; + Result res; + u_int32_t sizefs; + AFSStoreStatus storestatus; + AFSCallBack callback; + AFSVolSync volsync; + int ret; + + fid = &(vcp->fid); /* points to the VenusFid structure */ + fid = fid_translate(fid); + +#if 0 + arla_log(ADEBDISCONN, "reconnect: DISCONNECTED write on fid.Cell=0x%x, " + "fid.fid.Volume= 0x%x, fid.fid.Vnode=0x%x, fid.fid.Unique=0x%x", + fid->Cell, + fid->fid.Volume, + fid->fid.Vnode, + fid->fid.Unique); +#endif + + ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY); + assert (ce != NULL); + res.res = 0; + +#if 0 +/* Ba shier: should we send the file back to server? */ + if (XA_VALID_SIZE(xap)){ + res = cm_ftruncate (*fid, xap->xa_size, ce); + } +#endif + + ret = fcache_find(&fce, *fid); + assert (ret == 0); + tempce = fce; + + sizefs=fce->status.Length; + + /* some people have written to the file while we are disconnected */ + /* we have to give it a different name on the server */ + if (reconnect_mut_chk(fce, ce, vcp->DataVersion)) + { + VenusFid new_fid; + + alloc_fid_trans(fid); + reconnect_mut_newfile(&fce,vcp->cred.pag,&new_fid); + fce->status.Length = sizefs; + ReleaseWriteLock(&tempce->lock); + fill_fid_trans(&new_fid); + tempce->flags.attrp = FALSE; + tempce->flags.kernelp = FALSE; + } + +#if 0 + usedbytes -= entry->status.Length; + usedbytes += size; + + fce->status.Length = size; +#endif + + /* code from truncate file XXX join */ + conn = find_first_fs (fce, ce, &context); + + call = rx_NewCall (conn->connection); + if (call == NULL) { + arla_log (ADEBDISCONN, "Cannot call"); + res.res = ENOMEM; + goto out; + } + + storestatus.Mask = 0; + res.res = StartRXAFS_StoreData (call, + &(fce->fid.fid), + &storestatus, + 0, 0, fce->status.Length); + if(res.res) { + arla_log (ADEBDISCONN, "Could not start store, %s (%d)", + koerr_gettext(res.res), res.res); + rx_EndCall(call, 0); + goto out; + } + + sizefs = htonl (sizefs); + if (rx_Write (call, &sizefs, sizeof(sizefs)) != sizeof(sizefs)) { + res.res = rx_Error(call); + arla_log (ADEBDISCONN, "Error writing length: %d", res.res); + rx_EndCall(call, 0); + goto out; + } + + if (rx_Write (call, 0, 0) != 0) { + res.res = rx_Error(call); + arla_log (ADEBDISCONN, "Error writing: %d", res.res); + rx_EndCall(call, 0); + goto out; + } + + res.res = rx_EndCall (call, EndRXAFS_StoreData (call, + &status, + &callback, + &volsync)); + if (res.res) { + arla_log (ADEBDISCONN, "Error rx_EndCall: %s (%d)", + koerr_gettext(res.res), res.res); + goto out; + } + + fce->status = status; + fce->callback = callback; + fce->volsync = volsync; + + volcache_update_volsync (fce->volume, fce->volsync); + + /* code from write_attr XXX join */ + xfs_attr2afsstorestatus(xap, &storestatus); + + res.res = RXAFS_StoreStatus (conn->connection, + &fce->fid.fid, + &storestatus, + &status, + &volsync); + if (res.res) { + arla_log (ADEBDISCONN, "Could not make store-status call, %s (%d)", + koerr_gettext(res.res), res.res); + goto out; + } + arla_log(ADEBDISCONN, + "write_attr: status.Length = %d", status.Length); + fce->status = status; + fce->volsync = volsync; + + volcache_update_volsync (fce->volume, fce->volsync); + + out: + + free_fs_server_context(&context); + ReleaseWriteLock(&fce->lock); + cred_free(ce); + return res.res; +} + +/* + * + */ + +static int +reconnect_putdata(struct vcache *vcp) +{ + VenusFid *fid; + FCacheEntry *fce; + CredCacheEntry *ce; + Result res; + + u_int32_t sizefs; + int fd = -1; + struct rx_call *call; + ConnCacheEntry *conn; + fs_server_context context; + struct stat statinfo; + AFSStoreStatus storestatus; + AFSFetchStatus status; + AFSCallBack callback; + AFSVolSync volsync; + int ret; + + fid = &(vcp->fid); /* points to the VenusFid structure */ + arla_log(ADEBDISCONN, "reconnect: putdata before fid_translate, " + "fid->Cell=0x%x, fid->fid.Volume=0x%x, fid->fid.Vnode=0x%x, " + "fid->fid.Unique=0x%x", + fid->Cell, + fid->fid.Volume, + fid->fid.Vnode, + fid->fid.Unique); + + fid = fid_translate(fid); + + arla_log(ADEBDISCONN, "reconnect: putdata after fid_translate, " + "fid->Cell=0x%x, fid->fid.Volume=0x%x, fid->fid.Vnode=0x%x, " + "fid->fid.Unique=0x%x", + fid->Cell, + fid->fid.Volume, + fid->fid.Vnode, + fid->fid.Unique); + + + ce = cred_get (fid->Cell, vcp->cred.pag, CRED_ANY); + assert (ce != NULL); + + ret = fcache_find (&fce, *fid); + assert (ret == 0); + +#if 0 + isupdate = reconnect_mut_chk(fce, ce, vcp->DataVersion); + if (isupdate) + { + arla_log(ADEBDISCONN, + "reconnect_putdata: send data back because " + "the file was modified!"); + cred_free(ce); + ReleaseWriteLock(&fce->lock); + reconnect_mut_newfile(&fce, vcp->cred.pag); + return -1; + } + + if (reconnect_mut_chk (fce, ce)) { + arla_log (ADEBDISCONN, "Reconnect_putdata: can not send the file" + "to FS becausethis file has been modified!"); + ReleaseWriteLock(&fce->lock); + return -1; + } +#endif + + /* code taken from write_data XXX join */ + assert (CheckLock(&fce->lock) == -1); + + conn = find_first_fs (fce, ce, &context); + + fd = fcache_open_file (fce, O_RDONLY); + if (fd < 0) { + arla_log (ADEBDISCONN, "open %u failed", fce->index); + res.res = errno; + goto out; + } + + if (fstat (fd, &statinfo) < 0) { + arla_log (ADEBDISCONN, "Cannot stat file %u", fce->index); + res.res = errno; + goto out; + } + + sizefs = statinfo.st_size; + + call = rx_NewCall (conn->connection); + if (call == NULL) { + arla_log (ADEBDISCONN, "Cannot call"); + res.res = ENOMEM; + goto out; + } + + storestatus.Mask = 0; /* Dont save anything */ + res.res = StartRXAFS_StoreData (call, &fce->fid.fid, + &storestatus, + 0, + sizefs, + sizefs); + if (res.res) { + arla_log (ADEBDISCONN, "Could not start store, %s (%d)", + koerr_gettext(res.res), res.res); + rx_EndCall(call, 0); + goto out; + } + + res.res = copyfd2rx (fd, call, sizefs); + if (res.res) { + rx_EndCall(call, res.res); + arla_log (ADEBDISCONN, "copyfd2rx failed: %d", res.res); + goto out; + } + + res.res = rx_EndCall (call, EndRXAFS_StoreData (call, + &status, + &callback, + &volsync)); + if (res.res) { + arla_log (ADEBDISCONN, "Error rx_EndCall: %s (%d)", + koerr_gettext(res.res), res.res); + goto out; + } + if (status.DataVersion > fce->status.DataVersion) + arla_log(ADEBDISCONN, + "reconnect: putdata, server incremented DataVersion!"); + + fce->status = status; + fce->callback = callback; + fce->volsync = volsync; + + volcache_update_volsync (fce->volume, fce->volsync); + + out: + + ReleaseWriteLock(&fce->lock); + if (fd != -1) + close (fd); + free_fs_server_context (&context); + + cred_free(ce); + return res.res; +} + +/* + * + */ + +int reconnect_rename(struct vcache *vcp_old, struct vcache *vcp_new, + char *name_old, char *name_new) +{ + + FCacheEntry *fce_old, *fce_new; + CredCacheEntry *ce; + VenusFid *fid_old, *fid_new,foo_fid,*tempnew_fid; + int error; + + int ret = 0; + Result res; + char tmp[5]; + int isnewpar = 0; + ConnCacheEntry *conn; + fs_server_context context; + AFSFetchStatus orig_status, new_status; + AFSVolSync volsync; + xfs_cache_handle cache_handle; + + fid_old = &vcp_old->fid; + fid_old = fid_translate(fid_old); + + ret = fcache_find (&fce_old, *fid_old); + assert (ret == 0); + + /* ReleaseWriteLock(&fce_old->lock); SWW Qiyue 28 Maybe we dont need it*/ + assert(fce_old); + arla_log(ADEBDISCONN, "reconnect: old rename on Cell=0x%x, " + "fid.Volume= 0x%x, fid.Vnode=0x%x, fid.Unique=0x%x", + fce_old->fid.Cell, + fce_old->fid.fid.Volume, + fce_old->fid.fid.Vnode, + fce_old->fid.fid.Unique); + + fid_new = tempnew_fid = &vcp_new->fid; + fid_new = fid_translate(fid_new); + + if (tempnew_fid->fid.Volume != fid_new->fid.Volume || + tempnew_fid->fid.Vnode != fid_new->fid.Vnode || + tempnew_fid->fid.Unique != fid_new->fid.Unique) + isnewpar = 1; + +/*Ba ba: the parent dir was created during disconnected */ + + if (fid_old->fid.Volume == fid_new->fid.Volume && + fid_old->fid.Vnode == fid_new->fid.Vnode && + fid_old->fid.Unique == fid_new->fid.Unique ) + ReleaseWriteLock(&fce_old->lock); /* old and new are the same*/ + + ret = fcache_find (&fce_new, *fid_new); + assert (ret == 0); + + arla_log(ADEBDISCONN, "reconnect: new rename on Cell=0x%x, " + "fid.Volume= 0x%x, fid.Vnode=0x%x, fid.Unique=0x%x", + fce_new->fid.Cell, + fce_new->fid.fid.Volume, + fce_new->fid.fid.Vnode, + fce_new->fid.fid.Unique); + + + + arla_log(ADEBDISCONN, + "reconnect_rename: fce_old = 0x%x, fce_new = 0x%x", + fce_old, fce_new); + + ce = cred_get (vcp_old->fid.Cell, vcp_old->cred.pag, CRED_ANY); + assert (ce != NULL); + + assert (CheckLock(&fce_old->lock) == -1 + && CheckLock(&fce_new->lock) == -1); + + conn = find_first_fs (fce_old, ce, &context); + + error = RXAFS_Rename (conn->connection, + &fce_old->fid.fid, + name_old, + &fce_new->fid.fid, + name_new, + &orig_status, + &new_status, + &volsync); + + if (error) { + arla_log (ADEBDISCONN, "Could not Rename: %s (%d)", koerr_gettext(error), error); + goto out; } + + fce_old->status = orig_status; + fce_new->status = new_status; + + fce_old->volsync = fce_new->volsync = volsync; + + volcache_update_volsync (fce_old->volume, fce_old->volsync); + + +/*SWW Aug 01 */ + arla_warnx (ADEBDISCONN, + "reconnect_rename: we delete the old one %s volumn=0x%x, " + "vnode=0x%x,unique=0x%x", + name_old,fce_old->fid.fid.Volume, + fce_old->fid.fid.Vnode, + fce_old->fid.fid.Unique); + +/*Ba Yi: get the VenuseFid for new file */ + #if 0 + if (fid_old->fid.Volume == fid_new->fid.Volume && + fid_old->fid.Vnode == fid_new->fid.Vnode && + fid_old->fid.Unique == fid_new->fid.Unique ) ; +#endif + ReleaseWriteLock(&fce_old->lock); /* old and new are the same*/ + + error = adir_lookup (fce_old->fid, name_old, &foo_fid, ce); + +#if 0 + if (fid_old->fid.Volume == fid_new->fid.Volume && + fid_old->fid.Vnode == fid_new->fid.Vnode && + fid_old->fid.Unique == fid_new->fid.Unique ); +#endif + ObtainWriteLock (&fce_old->lock); + +/*Ba San: delete the old which was created during dis */ + if (error == 0) { + arla_warnx (ADEBDISCONN,"reconnect_rename: we delete the old one %s " + "volumn=0x%x,vnode=0x%x,unique=0x%x", + name_old, + foo_fid.fid.Volume, + foo_fid.fid.Vnode, + foo_fid.fid.Unique); + + adir_remove(fce_old,name_old); + adir_remove(fce_new,name_new); + + res = conv_dir (fce_old, ce, 0, &cache_handle, tmp, sizeof(tmp)); + + } else { + /* if found delete it */ +/*Ba San: try to find the previous VenuseFid for old name */ + if (error == ENOENT) { +#if 0 + if (fid_old->fid.Volume == fid_new->fid.Volume && + fid_old->fid.Vnode == fid_new->fid.Vnode && + fid_old->fid.Unique == fid_new->fid.Unique ); +#endif + ReleaseWriteLock(&fce_new->lock); + + error = adir_lookup (fce_new->fid, name_new, &foo_fid, ce); + +#if 0 + if (fid_old->fid.Volume == fid_new->fid.Volume && + fid_old->fid.Vnode == fid_new->fid.Vnode && + fid_old->fid.Unique == fid_new->fid.Unique ); +#endif + ObtainWriteLock (&fce_new->lock); + if (error == 0) /*Ba Si: We need delete the faked new */ + adir_remove(fce_new,name_new); + else if (error == ENOENT) { + int venusret; + + venusret = find_venus (name_new,&foo_fid); + assert (venusret==0); + arla_warnx (ADEBDISCONN,"I MUST WRITE A PROGRAM HERE"); + if (isnewpar == 1) { + + arla_warnx(ADEBDISCONN,"In reconnect_rename: " + "new Volume=0x%x,Vnode=0x%x,Unique=0x%x", + fce_new->fid.fid.Volume, + fce_new->fid.fid.Vnode, + fce_new->fid.fid.Unique); +#if 0 + error = adir_creat(fce_new, name_new, foo_fid.fid); +#endif + } + } + } + } + + arla_warnx (ADEBDISCONN,"reconnect_rename: we add the new one %s " + "volumn=0x%x,vnode=0x%x,unique=0x%x", + name_new, + foo_fid.fid.Volume, + foo_fid.fid.Vnode, + foo_fid.fid.Unique); + error = adir_creat (fce_new, name_new, foo_fid.fid); + res = conv_dir (fce_new, ce, 0, &cache_handle, tmp, sizeof(tmp)); + +/* Aug 1 */ + + out: + + free_fs_server_context (&context); + + ReleaseWriteLock(&fce_new->lock); + + if (fid_old->fid.Volume != fid_new->fid.Volume || + fid_old->fid.Vnode != fid_new->fid.Vnode || + fid_old->fid.Unique != fid_new->fid.Unique ) + ReleaseWriteLock(&fce_old->lock); /* old and new are the same*/ + + cred_free(ce); + return error; +} + +/* XXX */ + +/* + * + */ + +static void +recon_hashtabdel (FCacheEntry *e) +{ +} + +/* + * + */ + +static void +recon_hashtabadd (FCacheEntry *e) +{ +} + +/* + * + */ + +int reconnect_create(struct vcache *parent, struct vcache *child, char *name) +{ + + ConnCacheEntry *conn; + fs_server_context context; + VenusFid *parent_fid; + VenusFid *child_fid; + VenusFid fakeFid; + + CredCacheEntry *ce; + FCacheEntry *parentEntry; + FCacheEntry *childEntry; + + AFSFetchStatus fetch_attr; + AFSStoreStatus store_attr; + + Result res; + AFSFetchStatus status; + AFSCallBack callback; + AFSVolSync volsync; + int ret; + char tmp[5]; + xfs_cache_handle cache_handle; + int32_t type; + + parent_fid = &(parent->fid); /* points to the VenusFid structure */ + child_fid = &(child->fid); + fakeFid = *child_fid; + + /*Ba Liu: the parent dir may be created during dison mode*/ + parent_fid = fid_translate(parent_fid); + + ce = cred_get (parent->fid.Cell, parent->cred.pag, CRED_ANY); + assert (ce != NULL); + + ret = fcache_find (&parentEntry, *parent_fid); + assert (ret == 0); + +#if 0 + is_change = reconnect_mut_chk(parentEntry, + ce, + parentEntry->status.DataVersion); +#endif + +/*SWW Qiyue 30 delete the old file entry in dir */ + arla_warnx (ADEBDISCONN, + "reconnect_rename: we delete the old one volumn=0x%x, " + "vnode=0x%x,unique=0x%x", + parentEntry->fid.fid.Volume, + parentEntry->fid.fid.Vnode, + parentEntry->fid.fid.Unique); + + adir_remove(parentEntry,name); + + conn = find_first_fs (parentEntry, ce, &context); + + if (conn == NULL) { + arla_log (ADEBDISCONN, "Cannot call"); + res.res = ENOMEM; + goto out; + } + + ret = fcache_find (&childEntry, *child_fid); + assert (ret == 0); + + recon_hashtabdel(childEntry); + +#if 0 + fetch_attr = &childEntry->status; +#endif + + store_attr.Mask = 8; + store_attr.ClientModTime = childEntry->status.ClientModTime; + store_attr.Owner = childEntry->status.Owner; + store_attr.Group = childEntry->status.Group; + store_attr.UnixModeBits = childEntry->status.UnixModeBits; + store_attr.SegSize = childEntry->status.SegSize; + + arla_log(ADEBDISCONN, + "reconnect: create before RXAFS_CreateFile, " + "Cell=0x%x, fid.Volume= 0x%x, fid.Vnode=0x%x, fid.Unique=0x%x", + childEntry->fid.Cell, + childEntry->fid.fid.Volume, + childEntry->fid.fid.Vnode, + childEntry->fid.fid.Unique); + + alloc_fid_trans(&childEntry->fid); + + + ret = RXAFS_CreateFile (conn->connection, + &(parentEntry->fid.fid), + name, &store_attr, + &(childEntry->fid.fid), &fetch_attr, + &status, + &callback, + &volsync); + + if (ret) { + if (ret == 17) { + ReleaseWriteLock(&parentEntry->lock); + reconnect_mut_newfile(&childEntry, + parent->cred.pag, + &childEntry->fid); + ObtainWriteLock(&parentEntry->lock); + fill_fid_trans(&childEntry->fid); + recon_hashtabadd(childEntry); + childEntry->host = rx_HostOf (rx_PeerOf (conn->connection)); + update_kernelfid(fakeFid, childEntry->fid); + } else { + arla_log (ADEBDISCONN, "Could not CreateFile: %s (%d)", + koerr_gettext(ret), ret); + } + goto out; + } + + parentEntry->status = status; + parentEntry->callback = callback; + parentEntry->volsync = volsync; + + childEntry->fid.Cell = parentEntry->fid.Cell; + + arla_log(ADEBDISCONN, "reconnect: create after RXAFS_CreateFile, " + "Cell=0x%x, fid.Volume= 0x%x, fid .Vnode=0x%x, fid.Unique=0x%x", + childEntry->fid.Cell, + childEntry->fid.fid.Volume, + childEntry->fid.fid.Vnode, + childEntry->fid.fid.Unique); + + fill_fid_trans(&childEntry->fid); + +#if 0 + ReleaseWriteLock(&childEntry->lock); +#endif + + + ret = volcache_getbyid (childEntry->fid.fid.Volume, + childEntry->fid.Cell, + ce, + &childEntry->volume, + &type); + + recon_hashtabadd(childEntry); + + arla_log(ADEBDISCONN, + "reconnect: create after volcache_getbyid, Cell=0x%x, " + "fid.Volume= 0x%x, fid .Vnode=0x%x, fid.Unique=0x%x", + childEntry->fid.Cell, + childEntry->fid.fid.Volume, + childEntry->fid.fid.Vnode, + childEntry->fid.fid.Unique); + +/* SWW Qiyue 30: add the new file entry in dir */ + arla_warnx (ADEBDISCONN,"reconnect_rename: we add the new one " + "volumn=0x%x,vnode=0x%x,unique=0x%x", + parentEntry->fid.fid.Volume, + parentEntry->fid.fid.Vnode, + parentEntry->fid.fid.Unique); + + adir_creat (parentEntry, name, childEntry->fid.fid); + + childEntry->status = fetch_attr; + + childEntry->flags.attrp = TRUE; + childEntry->flags.kernelp = TRUE; + + childEntry->flags.datap = TRUE; + childEntry->tokens |= XFS_ATTR_R | XFS_DATA_R | XFS_DATA_W; + + volcache_update_volsync (parentEntry->volume, parentEntry->volsync); + + + +/*SWW Qiyue 28: Set the host for child entry */ + + childEntry->host = rx_HostOf (rx_PeerOf (conn->connection)); + assert(childEntry->host); + +/*SWW Qiyue 29: */ + arla_warnx (ADEBDISCONN, + "Replace fid.Volume=0x%x,Vnode=0x%x,Unique=0x%x with " + "Volume=0x%x,Vnode=0x%x,Unqiue=0x%x", + fakeFid.fid.Volume, + fakeFid.fid.Vnode, + fakeFid.fid.Unique, + childEntry->fid.fid.Volume, + childEntry->fid.fid.Vnode, + childEntry->fid.fid.Unique); + + update_kernelfid(fakeFid, childEntry->fid); + + conv_dir(parentEntry, ce, 0, &cache_handle, tmp, sizeof(tmp)); + + ReleaseWriteLock(&childEntry->lock); + + out: + + ReleaseWriteLock(&parentEntry->lock); + ReleaseWriteLock(&childEntry->lock); + free_fs_server_context(&context); + cred_free(ce); + return ret; +} + +/* + * + */ + +int reconnect_mkdir(struct vcache *parent, struct vcache *curdir, + AFSStoreStatus *store_status, char *name) +{ + ConnCacheEntry *conn; + fs_server_context context; + CredCacheEntry *ce; + VenusFid *parent_fid; + VenusFid *child_fid; + VenusFid fakeFid; + + FCacheEntry *parentEntry, *childEntry, *tempEntry, *tempparEntry; + Result tempres; + Result res; + int ret = 0; + int tempret = 0; + struct timeval tv; + char tmp[5]; + + AFSFid Outfid; /* Ba Wu: These are used to get the info from FS*/ + AFSFetchStatus fetch_attr; + AFSFetchStatus status; + AFSCallBack callback; + AFSVolSync volsync; + xfs_cache_handle cache_handle; + int32_t type; + + parent_fid = &(parent->fid); /* points to the VenusFid structure */ + child_fid = &(curdir->fid); + fakeFid = *child_fid; + + parent_fid = fid_translate(parent_fid); + + ce = cred_get (parent->fid.Cell, parent->cred.pag, CRED_ANY); + assert (ce != NULL); + + ret = fcache_find (&parentEntry, *parent_fid); + assert (ret == 0); + + tempparEntry = parentEntry; + +/*Ba ba: used to check whether name can be find Deleted !!! + ReleaseWriteLock(&parentEntry->lock); + tempret = adir_lookup (parentEntry->fid , name , &foo_fid , ce); */ +/*Ba ba: used to check whether name can be find Deleted !!! */ + + /*Ba Wu Remove the dir name from itsparent dir */ + tempret = adir_remove(parentEntry,name); + conn = find_first_fs (parentEntry, ce, &context); + + if (conn == NULL) { + arla_log (ADEBDISCONN,"Cannot make this connection"); + res.res = ENOMEM; + goto out; + } + + ret = fcache_find(&childEntry, *child_fid);/*Ba Wu: remove the newly created dir */ + assert (ret == 0); + + recon_hashtabdel(childEntry); + + alloc_fid_trans(&childEntry->fid); + + gettimeofday(&tv, NULL); + + ret = RXAFS_MakeDir (conn->connection, + &parentEntry->fid.fid, + name, + store_status, + &Outfid, + &fetch_attr, + &status, + &callback, + &volsync); + + if (ret) { + arla_log (ADEBDISCONN, "Could not CreateFile: %s (%d)", + koerr_gettext(ret), ret); + goto out; + } + + parentEntry->status = status; + parentEntry->callback = callback; + parentEntry->callback.ExpirationTime += tv.tv_sec; + parentEntry->volsync = volsync; + + childEntry->fid.Cell = parentEntry->fid.Cell; + childEntry->fid.fid = Outfid; + childEntry->status = fetch_attr; + childEntry->flags.attrp = TRUE; + childEntry->flags.kernelp = TRUE; + childEntry->flags.datap = TRUE; + childEntry->tokens |= XFS_ATTR_R | XFS_DATA_R | XFS_DATA_W; + + fill_fid_trans(&childEntry->fid); + + ret = volcache_getbyid (childEntry->fid.fid.Volume, + childEntry->fid.Cell, + ce, + &childEntry->volume, + &type); + + recon_hashtabadd(childEntry); + +/*Ba ba: Need to change later!!! */ +#if 0 + ReleaseWriteLock(&tempparEntry->lock); + tempret = adir_changefid (tempparEntry->fid ,name, &Outfid, ce); + ReleaseWriteLock(&tempparEntry->lock); + tempret = adir_lookup (tempparEntry->fid ,name, &foo_fid, ce); +#endif + + tempret = adir_creat (parentEntry, name, childEntry->fid.fid); + + tempret = adir_mkdir (childEntry, childEntry->fid.fid,parentEntry->fid.fid); + + childEntry->host = rx_HostOf (rx_PeerOf (conn->connection)); + assert(childEntry->host); + + update_kernelfid(fakeFid, childEntry->fid); + + tempres = conv_dir(parentEntry, ce, 0, &cache_handle, + tmp, sizeof(tmp)); + + ReleaseWriteLock(&childEntry->lock); + + /*SWW Qiyue 29: This should be deleted later */ + ret = fcache_find (&tempEntry, childEntry->fid); + + assert (ret == 0); + assert (tempEntry == NULL); + + out: + + ReleaseWriteLock(&parentEntry->lock); + ReleaseWriteLock(&childEntry->lock); + free_fs_server_context(&context); + cred_free(ce); + return ret; +} + +/* + * + */ + +int reconnect_link(struct vcache *parent, struct vcache *existing, + char *name) +{ + ConnCacheEntry *conn; + fs_server_context context; + CredCacheEntry *ce; + VenusFid *parent_fid; + VenusFid *existing_fid; + char tmp[5]; + int ret = 0; + FCacheEntry *dir_entry,*existing_entry; + Result res; + + AFSFetchStatus new_status; + AFSFetchStatus status; + AFSVolSync volsync; + xfs_cache_handle cache_handle; + + + parent_fid = &(parent->fid); + existing_fid = &(existing->fid); + + parent_fid = fid_translate(parent_fid); + + ce = cred_get (parent->fid.Cell, parent->cred.pag, CRED_ANY); + assert (ce != NULL); + + ret = fcache_find (&dir_entry, *parent_fid); + assert (ret == 0); + + ret = fcache_find (&existing_entry, *existing_fid); + assert (ret == 0); + + conn = find_first_fs (dir_entry, ce, &context); + + if (conn == NULL) { + arla_log (ADEBDISCONN,"Cannot make this connection"); + res.res = ENOMEM; + goto out; + } + + ret = RXAFS_Link (conn->connection, + &dir_entry->fid.fid, + name, + &existing_entry->fid.fid, + &new_status, + &status, + &volsync); + if (ret) { + arla_warn (ADEBFCACHE, ret, "Link"); + goto out; + } + + dir_entry->status = status; + dir_entry->volsync = volsync; + + existing_entry->status = new_status; + + volcache_update_volsync (dir_entry->volume, dir_entry->volsync); + + res = conv_dir (dir_entry, ce, 0, &cache_handle, tmp, sizeof(tmp)); + + out: + ReleaseWriteLock(&dir_entry->lock); + ReleaseWriteLock(&existing_entry->lock); + free_fs_server_context (&context); + return ret; +} + +/* + * + */ + +int reconnect_symlink(struct vcache *parent, struct vcache *child, + AFSStoreStatus *store_attr, char *name, + char *contents) +{ + ConnCacheEntry *conn; + fs_server_context context; + CredCacheEntry *ce; + VenusFid *parent_fid, *child_fid, fakeFid; + char tmp[5]; + int ret = 0; + FCacheEntry *dir_entry, *childEntry; + Result res; + + AFSFetchStatus fetch_attr, new_status; + AFSVolSync volsync; + xfs_cache_handle cache_handle; + int32_t type; + + parent_fid = &(parent->fid); + child_fid = &(child->fid); + fakeFid = *child_fid; + parent_fid = fid_translate(parent_fid); + + ce = cred_get (parent->fid.Cell, parent->cred.pag, CRED_ANY); + assert (ce != NULL); + + ret = fcache_find (&dir_entry, *parent_fid); + assert (ret == 0); + + adir_remove(dir_entry,name); + + ret = fcache_find (&childEntry, *child_fid); + assert (ret == 0); + + recon_hashtabdel(childEntry); + + assert(ret==0); + conn = find_first_fs (dir_entry, ce, &context); + + if (conn == NULL) { + arla_log (ADEBDISCONN,"Cannot make this connection"); + goto out; + } + + alloc_fid_trans(&childEntry->fid); + + ret = RXAFS_Symlink (conn->connection, + &dir_entry->fid.fid, + name, + contents, + store_attr, + &(childEntry->fid.fid), + &fetch_attr, + &new_status, + &volsync); + if (ret) { + arla_warn (ADEBFCACHE, ret, "Symlink"); + goto out; + } + + child_fid->Cell = dir_entry->fid.Cell; + + fill_fid_trans (&childEntry->fid); + ret = volcache_getbyid (childEntry->fid.fid.Volume, + childEntry->fid.Cell, + ce, + &childEntry->volume, + &type); + + recon_hashtabadd (childEntry); + + adir_creat(dir_entry, name, childEntry->fid.fid); + + childEntry->status = fetch_attr; + childEntry->flags.attrp = TRUE; + childEntry->flags.kernelp = TRUE; + childEntry->tokens |= XFS_ATTR_R; + volcache_update_volsync (dir_entry->volume, dir_entry->volsync); + + childEntry->host = rx_HostOf (rx_PeerOf (conn->connection)); + assert(childEntry->host); + + update_kernelfid(fakeFid, childEntry->fid); + res = conv_dir (dir_entry, ce, 0, &cache_handle, tmp, sizeof(tmp)); + + out: + ReleaseWriteLock(&dir_entry->lock); + ReleaseWriteLock(&childEntry->lock); + free_fs_server_context(&context); + cred_free(ce); + return ret; +} + diff --git a/usr.sbin/afs/src/arlad/reconnect.h b/usr.sbin/afs/src/arlad/reconnect.h new file mode 100644 index 00000000000..de1b829a26e --- /dev/null +++ b/usr.sbin/afs/src/arlad/reconnect.h @@ -0,0 +1,39 @@ +/* $OpenBSD: reconnect.h,v 1.1 1999/04/30 01:59:10 art Exp $ */ +/* COPYRIGHT (C) 1998 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS + * AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS + * FOR ANY PURPOSE, SO LONG AS THE NAME OF THE UNIVERSITY OF + * MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY + * PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE + * WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. IF THE + * ABOVE COPYRIGHT NOTICE OR ANY OTHER IDENTIFICATION OF THE + * UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY + * PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST + * ALSO BE INCLUDED. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +/* $KTH: reconnect.h,v 1.3 1998/12/21 21:54:43 assar Exp $ */ + +#ifndef _RECONNECT_H +#define _RECONNECT_H + +void +do_replay(char *log_file, int log_entries, VenusFid *changed_fid); + +#endif /* _RECONNECT_H */ diff --git a/usr.sbin/afs/src/lib/ko/vlmisc.c b/usr.sbin/afs/src/lib/ko/vlmisc.c new file mode 100644 index 00000000000..4db702f96b3 --- /dev/null +++ b/usr.sbin/afs/src/lib/ko/vlmisc.c @@ -0,0 +1,92 @@ +/* $OpenBSD: vlmisc.c,v 1.1 1999/04/30 01:59:11 art Exp $ */ +/* + * Copyright (c) 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ko_locl.h" + +RCSID("$KTH: vlmisc.c,v 1.1 1999/03/03 15:33:21 assar Exp $"); + +/* + * Convert old style vldbentry `old` to newer vldbNentry style `new' + */ + +void +vldb2vldbN (const vldbentry *old, nvldbentry *new) +{ + int i; + + strncpy (new->name, old->name, VLDB_MAXNAMELEN); + new->name[VLDB_MAXNAMELEN-1] = '\0'; + if (old->nServers > MAXNSERVERS) + new->nServers = MAXNSERVERS; + else + new->nServers = old->nServers; + + for (i = 0; i < new->nServers ; i++) { + new->serverNumber[i] = old->serverNumber[i]; + new->serverPartition[i] = old->serverPartition[i]; + new->serverFlags[i] = old->serverFlags[i]; + } + for (i = 0; i < MAXTYPES ; i++) + new->volumeId[i] = old->volumeId[i]; + new->cloneId = old->cloneId; + new->flags = old->flags; +} + +void +volintInfo2xvolintInfo (const volintInfo *old, xvolintInfo *new) +{ + memset (new, 0, sizeof(*new)); + strcpy (new->name, old->name); + new->volid = old->volid; + new->type = old->type; + new->backupID = old->backupID; + new->parentID = old->parentID; + new->cloneID = old->cloneID; + new->status = old->status; + new->copyDate = old->copyDate; + new->inUse = old->inUse; + new->creationDate = old->creationDate; + new->accessDate = old->accessDate; + new->updateDate = old->updateDate; + new->backupDate = old->backupDate; + new->dayUse = old->dayUse; + new->filecount = old->filecount; + new->maxquota = old->maxquota; + new->size = old->size; +} diff --git a/usr.sbin/afs/src/lwp/plwp.c b/usr.sbin/afs/src/lwp/plwp.c new file mode 100644 index 00000000000..62509a78b1e --- /dev/null +++ b/usr.sbin/afs/src/lwp/plwp.c @@ -0,0 +1,939 @@ +/* $OpenBSD: plwp.c,v 1.1 1999/04/30 01:59:13 art Exp $ */ +/* This version of the code is derived from the Coda version of the LWP + * library, which can be compiled as a wrapper around Mach cthreads + */ +/* +**************************************************************************** +* Copyright IBM Corporation 1988, 1989 - All Rights Reserved * +* * +* Permission to use, copy, modify, and distribute this software and its * +* documentation for any purpose and without fee is hereby granted, * +* provided that the above copyright notice appear in all copies and * +* that both that copyright notice and this permission notice appear in * +* supporting documentation, and that the name of IBM not be used in * +* advertising or publicity pertaining to distribution of the software * +* without specific, written prior permission. * +* * +* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM * +* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY * +* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * +* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * +* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * +**************************************************************************** +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* allocate externs here */ +#define LWP_KERNEL + +#include <lwp.h> + +RCSID("$KTH: plwp.c,v 1.2 1999/02/02 00:47:16 assar Exp $"); + +#ifdef AFS_AIX32_ENV +#include <ulimit.h> +#include <sys/errno.h> +#include <sys/user.h> +#include <sys/pseg.h> +#include <sys/core.h> +#pragma alloca +#endif + +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +extern char PRE_Block; /* from preempt.c */ + +#define ON 1 +#define OFF 0 +#define TRUE 1 +#define FALSE 0 +#define READY 2 +#define WAITING 3 +#define DESTROYED 4 +#define QWAITING 5 +#define MAXINT (~(1<<((sizeof(int)*8)-1))) +#define MINSTACK 44 + + +/* Debugging macro */ +#ifdef DEBUG +#define Debug(level, msg)\ + if (lwp_debug && lwp_debug >= level) {\ + printf("***LWP (%p): ", lwp_cpptr);\ + printf msg;\ + putchar('\n');\ + } + +#else +#define Debug(level, msg) +#endif + +/* Prototypes */ +static void Abort_LWP(char *msg) ; +static void Dispatcher(void); +static void Create_Process_Part2(PROCESS temp); +static void purge_dead_pcbs(void) ; +static void Dispose_of_Dead_PCB (PROCESS cur) ; +static void Free_PCB(PROCESS pid) ; +static void Exit_LWP(); +static void Initialize_PCB(PROCESS temp, int priority, char *stack, + int stacksize, void (*ep)() , char *parm, + char *name) ; +static int Internal_Signal(register char *event) ; +char (*RC_to_ASCII()); + +#define MAX_PRIORITIES (LWP_MAX_PRIORITY+1) + +struct QUEUE { + PROCESS head; + int count; +} runnable[MAX_PRIORITIES], blocked; +/* + * Invariant for runnable queues: The head of each queue points to the + * currently running process if it is in that queue, or it points to the + * next process in that queue that should run. + */ + +/* special user-tweakable option for AIX */ +int lwp_MaxStackSize = 32768; +int lwp_MaxStackSeen = 0; + +int lwp_nextindex = 0; + +/* Iterator macro */ +#define for_all_elts(var, q, body)\ + {\ + register PROCESS var, _NEXT_;\ + register int _I_;\ + for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\ + _NEXT_ = var -> next;\ + body\ + }\ + } + +static struct lwp_ctl *lwp_init = 0; + +static void Dump_One_Process(PROCESS pid); +static void Dump_Processes(); +static void Delete_PCB(register PROCESS pid); +static void Free_PCB(PROCESS pid); +static void Cal_Highest_runnable_priority(); +static int InitializeProcessSupport(int, PROCESS *); + +PROCESS lwp_cpptr; + +/* The global Highest_runnable_priority is only needed in NEW lwp. + But it gets set within a for_all_elts() instance in + InternalSignal(). */ +int Highest_runnable_priority; /* global variable for max priority */ + +int Proc_Running; /* indicates forked proc got control */ + +pthread_mutex_t run_sem, ct_mutex; + +static void +lwpremove(register PROCESS p, register struct QUEUE *q) +{ + /* Special test for only element on queue */ + if (q->count == 1) + q -> head = NULL; + else { + /* Not only element, do normal remove */ + p -> next -> prev = p -> prev; + p -> prev -> next = p -> next; + } + /* See if head pointing to this element */ + if (q->head == p) q -> head = p -> next; + q->count--; + Debug(0, ("removing, count now %d", q->count)); + p -> next = p -> prev = NULL; +} + +static void +lwpinsert(register PROCESS p, register struct QUEUE *q) +{ + if (q->head == NULL) { /* Queue is empty */ + q -> head = p; + p -> next = p -> prev = p; + } else { /* Regular insert */ + p -> prev = q -> head -> prev; + q -> head -> prev -> next = p; + q -> head -> prev = p; + p -> next = q -> head; + } + q->count++; + Debug(0, ("inserting, count now %d", q->count)); +} + +static void +lwpmove(PROCESS p, struct QUEUE *from, struct QUEUE *to) +{ + lwpremove(p, from); + lwpinsert(p, to); +} + +int +LWP_TerminateProcessSupport() /* terminate all LWP support */ +{ + register int i; + + Debug(0, ("Entered Terminate_Process_Support")); + if (lwp_init == NULL) return LWP_EINIT; + /* free all space allocated */ + for (i=0; i<MAX_PRIORITIES; i++) + for_all_elts(cur, runnable[i], { Free_PCB(cur);}) + for_all_elts(cur, blocked, { Free_PCB(cur);}) + free((char *)lwp_init); + lwp_init = NULL; + return LWP_SUCCESS; +} + +int +LWP_GetRock(int Tag, char **Value) +{ + /* Obtains the pointer Value associated with the rock Tag of this LWP. + Returns: + LWP_SUCCESS if specified rock exists and Value has been filled + LWP_EBADROCK rock specified does not exist + */ + register int i; + register struct rock *ra; + + ra = lwp_cpptr->rlist; + + for (i = 0; i < lwp_cpptr->rused; i++) + if (ra[i].tag == Tag) { +#ifdef PTHREAD_GETSPECIFIC_TWOARG + pthread_getspecific(ra[i].val, Value); +#else + *Value = pthread_getspecific(ra[i].val); +#endif + /**Value = ra[i].value;*/ + return(LWP_SUCCESS); + } + return(LWP_EBADROCK); +} + + +int +LWP_NewRock(int Tag, char *Value) +{ + /* Finds a free rock and sets its value to Value. + Return codes: + LWP_SUCCESS Rock did not exist and a new one was used + LWP_EBADROCK Rock already exists. + LWP_ENOROCKS All rocks are in use. + + From the above semantics, you can only set a rock value once. + This is specifically to prevent multiple users of the LWP + package from accidentally using the same Tag value and + clobbering others. You can always use one level of + indirection to obtain a rock whose contents can change. */ + + register int i; + register struct rock *ra; /* rock array */ + + ra = lwp_cpptr->rlist; + + /* check if rock has been used before */ + for (i = 0; i < lwp_cpptr->rused; i++) + if (ra[i].tag == Tag) return(LWP_EBADROCK); + + /* insert new rock in rock list and increment count of rocks */ + if (lwp_cpptr->rused < MAXROCKS) { + ra[lwp_cpptr->rused].tag = Tag; +#ifdef HAVE_PTHREAD_KEYCREATE + if (pthread_keycreate(&ra[lwp_cpptr->rused].val, NULL)) +#else + if (pthread_key_create(&ra[lwp_cpptr->rused].val, NULL)) +#endif + return(LWP_EBADROCK); + if (pthread_setspecific(ra[lwp_cpptr->rused].val, Value)) + return(LWP_EBADROCK); + /* ra[lwp_cpptr->rused].value = Value; */ + lwp_cpptr->rused++; + return(LWP_SUCCESS); + } + else return(LWP_ENOROCKS); +} + +static void +Dispose_of_Dead_PCB(PROCESS cur) +{ + + Debug(0, ("Entered Dispose_of_Dead_PCB")); + Delete_PCB(cur); + Free_PCB(cur); +} + +int +LWP_CurrentProcess(PROCESS *pid) +{ + Debug(0, ("Entered Current_Process")); + if (lwp_init) { + *pid = lwp_cpptr; + return LWP_SUCCESS; + } else + return LWP_EINIT; +} + + +int +LWP_GetProcessPriority(PROCESS pid, int *priority) +{ + Debug(0, ("Entered Get_Process_Priority")); + if (lwp_init) { + *priority = pid -> priority; + return 0; + } else + return LWP_EINIT; +} + +int +LWP_WaitProcess(char *event) +{ + char *tempev[2]; + + Debug(0, ("Entered Wait_Process")); + if (event == NULL) return LWP_EBADEVENT; + tempev[0] = event; + tempev[1] = NULL; + return LWP_MwaitProcess(1, tempev); +} + +static void +Delete_PCB(register PROCESS pid) +{ + Debug(0, ("Entered Delete_PCB")); + lwpremove(pid, (pid->blockflag || pid->status==WAITING || + pid->status==DESTROYED ? &blocked + : &runnable[pid->priority])); +} + +static void +purge_dead_pcbs() +{ + for_all_elts(cur, blocked, { if (cur->status == DESTROYED) + Dispose_of_Dead_PCB(cur); }) +} + +static void +Exit_LWP() +{ + exit (-1); +} + +static void +Dump_Processes() +{ + if (lwp_init) { + register int i; + for (i=0; i<MAX_PRIORITIES; i++) + for_all_elts(x, runnable[i], { + printf("[Priority %d]\n", i); + Dump_One_Process(x); + }) + for_all_elts(x, blocked, { Dump_One_Process(x); }) + } else + printf("***LWP: LWP support not initialized\n"); +} + +char * +LWP_Name() +{ + return(lwp_cpptr->name); +} + +int +LWP_Index() +{ + return(lwp_cpptr->index); +} + +int +LWP_HighestIndex() +{ + return(lwp_nextindex-1); +} + +/* A process calls this routine to wait until somebody signals it. + * LWP_QWait removes the calling process from the runnable queue + * and makes the process sleep until some other process signals via LWP_QSignal + */ +int +LWP_QWait() +{ + PROCESS old_cpptr; + + Debug(0, ("LWP_QWait: %s is going to QWait\n", lwp_cpptr->name)); + lwp_cpptr->status = QWAITING; + if (runnable[lwp_cpptr->priority].count == 0) + Cal_Highest_runnable_priority(); + + old_cpptr = lwp_cpptr; + + /* wake up next lwp */ + lwp_cpptr = runnable[Highest_runnable_priority].head; + lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]); + timerclear(&lwp_cpptr->lastReady); + pthread_mutex_lock(&ct_mutex); + Debug(0, ("LWP_QWait:%s going to wake up %s \n", old_cpptr->name, + lwp_cpptr->name)); + pthread_cond_signal(&lwp_cpptr->c); + + /* sleep on your own condition */ + Debug(0, ("LWP_QWait:%s going to wait on own condition \n", + old_cpptr->name)); + pthread_cond_wait(&old_cpptr->c, &ct_mutex); + pthread_mutex_unlock(&ct_mutex); + + lwp_cpptr = old_cpptr; + + /* return only if calling process' priority is the highest */ + if (lwp_cpptr->priority < Highest_runnable_priority) + Dispatcher(); + return LWP_SUCCESS; +} + + +/* signal the PROCESS pid - by adding it to the runnable queue */ +int +LWP_QSignal(PROCESS pid) +{ + if (pid->status == QWAITING) { + Debug(0, ("LWP_Qsignal: %s is going to QSignal %s\n", lwp_cpptr->name, + pid->name)); + pid->status = READY; + lwpinsert(pid, &runnable[pid->priority]); + Debug(0, ("LWP_QSignal: Just inserted %s into runnable queue\n", + pid->name)); + gettimeofday(&pid->lastReady, 0); + Highest_runnable_priority = + MAX(Highest_runnable_priority, pid->priority); + Debug(0, ("%s priority= %d; HRP = %d; Signalled process pri = %d", + lwp_cpptr->name, lwp_cpptr->priority, + Highest_runnable_priority, pid->priority)); + return LWP_SUCCESS; + } + else return LWP_ENOWAIT; +} + + +int +LWP_CreateProcess(void (*ep)(), int stacksize, int priority, + char *parm, char *name, PROCESS *pid) +{ + PROCESS temp; + pthread_t ct; + pthread_attr_t cta; + PROCESS old_cpptr; + int retval; + + Debug(0, ("Entered LWP_CreateProcess to create %s at priority %d\n", + name, priority)); + old_cpptr = lwp_cpptr; + /* Throw away all dead process control blocks */ + purge_dead_pcbs(); + + if (lwp_init) { + /* allocate the memory for the pcb - check for malloc errors */ + temp = (PROCESS)malloc (sizeof (struct lwp_pcb)); + if (temp == NULL) { + Dispatcher(); + return LWP_ENOMEM; + } + + /* check priorities */ + if (priority < 0 || priority >= MAX_PRIORITIES) { + Dispatcher(); + return LWP_EBADPRI; + } + + Initialize_PCB(temp, priority, NULL, 0, ep, parm, name); + + /* make the process runnable by placing it in the runnable q */ + lwpinsert(temp, &runnable[priority]); + gettimeofday(&temp->lastReady, 0); + + if (PRE_Block != 0) Abort_LWP("PRE_Block not 0"); + + PRE_Block = 1; + Proc_Running = FALSE; /* sem set true by forked process */ + + pthread_attr_init(&cta); +#ifdef _POSIX_THREAD_ATTR_STACKSIZE + pthread_attr_setstacksize(&cta, stacksize); +#endif + retval = pthread_create(&ct, &cta, (void *)Create_Process_Part2, temp); + if (!retval) { + temp->a = cta; + pthread_detach(ct); + + /* check if max priority has changed */ + Highest_runnable_priority = MAX(Highest_runnable_priority, priority); + + pthread_mutex_lock(&run_sem); + Debug(0, ("Before creating process yields Proc_Running = %d\n", + Proc_Running)); + while( !Proc_Running ){ + pthread_mutex_unlock(&run_sem); +#if defined(HAVE_THR_YIELD) + thr_yield(); +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + sched_yield(); +#else + pthread_yield(); +#endif + pthread_mutex_lock(&run_sem); + Debug(0,("After creating proc yields and gets back control Proc_Running = %d\n", + Proc_Running)); + } + pthread_mutex_unlock(&run_sem); + + lwp_cpptr = old_cpptr; + + Dispatcher(); + *pid = temp; + return LWP_SUCCESS; + } + } else { + pthread_attr_destroy(&cta); + } + return LWP_EINIT; +} + +int +LWP_DestroyProcess(PROCESS pid) +{ + void *t; + + Debug(0, ("Entered Destroy_Process")); + if (lwp_init) { + pthread_attr_destroy(&pid->a); + if (lwp_cpptr == pid){ + /* kill myself */ + pid->status = DESTROYED; + Free_PCB(pid); + Cal_Highest_runnable_priority(); + + /* Calculate next runnable lwp and signal it */ + lwp_cpptr = runnable[Highest_runnable_priority].head; + lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]); + + pthread_mutex_lock(&ct_mutex); + pthread_cond_signal(&lwp_cpptr->c); + pthread_mutex_unlock(&ct_mutex); + pthread_exit(t); + } else { + /* kill some other process - mark status destroyed - + if process is blocked, it will be purged on next create proc; + if it is runnable the dispatcher will kill it */ + pid->status = DESTROYED ; + Dispatcher(); + } + return LWP_SUCCESS ; + } else + return LWP_EINIT; +} + +int +LWP_DispatchProcess() /* explicit voluntary preemption */ +{ + Debug(0, ("Entered Dispatch_Process")) + if (lwp_init) { + Dispatcher(); + return LWP_SUCCESS; + } else + return LWP_EINIT; +} + +int +LWP_Init(int version, int priority, PROCESS *pid) +{ + if (version != LWP_VERSION) + { + fprintf(stderr, "**** FATAL ERROR: LWP VERSION MISMATCH ****\n"); + exit(-1); + } + else return(InitializeProcessSupport(priority, pid)); +} + +int +LWP_InitializeProcessSupport(int priority, PROCESS *pid) +{ + return(InitializeProcessSupport(priority, pid)); +} + +static int +InitializeProcessSupport(int priority, PROCESS *pid) +{ + PROCESS temp; + register int i; + + Debug(0, ("Entered InitializeProcessSupport")); + if (lwp_init != NULL) return LWP_SUCCESS; + + /* check priorities and set up running and blocked queues */ + if (priority >= MAX_PRIORITIES) return LWP_EBADPRI; + for (i=0; i<MAX_PRIORITIES; i++) { + runnable[i].head = NULL; + runnable[i].count = 0; + } + blocked.head = NULL; + blocked.count = 0; + lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl)); + temp = (PROCESS) malloc(sizeof(struct lwp_pcb)); + if (lwp_init == NULL || temp == NULL) + Abort_LWP("Insufficient Storage to Initialize LWP Support"); + + /* check parameters */ + Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,"Main Process"); + gettimeofday(&temp->lastReady, 0); + + Highest_runnable_priority = priority; + + /* initialize mutex and semaphore */ + Proc_Running = TRUE; + pthread_mutex_init(&run_sem, NULL); + pthread_mutex_init(&ct_mutex, NULL); + + lwp_cpptr = temp; + Dispatcher(); + *pid = temp; + return LWP_SUCCESS; +} + +int +LWP_INTERNALSIGNAL(void *event, int yield) +{ + Debug(0, ("Entered LWP_SignalProcess, yield=%d", yield)); + if (lwp_init) { + int rc; + rc = Internal_Signal(event); + if (yield) { + Cal_Highest_runnable_priority(); + Debug(0, ("hipri=%d", Highest_runnable_priority)); + Dispatcher(); + } + return rc; + } else + return LWP_EINIT; +} + +int +LWP_MwaitProcess(int wcount, char *evlist[]) /* wait on m of n events */ +{ + register int ecount, i; + PROCESS old_cpptr; + + Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount)); + if (evlist == NULL) { + Dispatcher(); + return LWP_EBADCOUNT; + } + + /* count # of events in eventlist */ + for (ecount = 0; evlist[ecount] != NULL; ecount++) ; + if (ecount == 0) { + Dispatcher(); + return LWP_EBADCOUNT; + } + + if (lwp_init) { + /* check for illegal counts */ + if (wcount>ecount || wcount<0) { + Dispatcher(); + return LWP_EBADCOUNT; + } + + /* reallocate eventlist if new list has more elements than before */ + if (ecount > lwp_cpptr->eventlistsize) { + lwp_cpptr->eventlist = + (char **)realloc((char *)lwp_cpptr->eventlist, + ecount*sizeof(char *)); + lwp_cpptr->eventlistsize = ecount; + } + + /* place events in eventlist of the pcb */ + for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i]; + + /* if there are any events to wait on then set status to + WAITING and place the pcb in blocked queue */ + if (wcount > 0) { + lwp_cpptr -> status = WAITING; + lwpinsert(lwp_cpptr, &blocked); + } + lwp_cpptr -> wakevent = 0; /* index of eventid causing wakeup */ + lwp_cpptr -> waitcnt = wcount; + lwp_cpptr -> eventcnt = ecount; + if (runnable[lwp_cpptr->priority].count == 0) + Cal_Highest_runnable_priority(); + old_cpptr = lwp_cpptr; + + /* wake up next lwp */ + lwp_cpptr = runnable[Highest_runnable_priority].head; + lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]); + timerclear(&lwp_cpptr->lastReady); + Debug(0, ("WaitProcess: %s Going to signal %s \n", + old_cpptr->name, lwp_cpptr->name)) + pthread_mutex_lock(&ct_mutex); + pthread_cond_signal(&lwp_cpptr->c); + + /* sleep on your own condition */ + Debug(0, ("WaitProcess:%s going to wait \n", old_cpptr->name)) + pthread_cond_wait(&old_cpptr->c, &ct_mutex); + pthread_mutex_unlock(&ct_mutex); + + /* update the global pointer */ + lwp_cpptr = old_cpptr; + if (lwp_cpptr->priority < Highest_runnable_priority) + Dispatcher(); + return LWP_SUCCESS ; + } + return LWP_EINIT ; + +} + +int +LWP_StackUsed(PROCESS pid, int *max, int *used) +{ + /* just here for compatibility */ + *max = -1; + *used = -1; + return LWP_SUCCESS; +} + +static void +Abort_LWP(char *msg) +{ + Debug(0, ("Entered Abort_LWP")) + printf("***LWP Abort: %s\n", msg); + Dump_Processes(); + Exit_LWP(); +} + +static void +Create_Process_Part2(PROCESS temp) +{ + /* set the global Proc_Running to signal the parent */ + pthread_mutex_lock(&run_sem); + Proc_Running = TRUE; + pthread_cond_wait(&temp->c, &run_sem); + pthread_mutex_unlock(&run_sem); + lwp_cpptr = temp; + +#ifdef _POSIX_THREAD_ATTR_STACKSIZE + pthread_attr_setstacksize(&temp->a, temp->stacksize); +#endif + + (*temp->ep)(temp->parm); + LWP_DestroyProcess(temp); +} + +static void +Dump_One_Process(PROCESS pid) +{ + int i; + + printf("***LWP: Process Control Block at 0x%x\n", (int)pid); + printf("***LWP: Name: %s\n", pid->name); + if (pid->ep != NULL) + printf("***LWP: Initial entry point: 0x%x\n", (int)pid->ep); + if (pid->blockflag) printf("BLOCKED and "); + switch (pid->status) { + case READY: printf("READY"); break; + case WAITING: printf("WAITING"); break; + case DESTROYED: printf("DESTROYED"); break; + default: printf("unknown"); + } + putchar('\n'); + printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", + pid->priority, (int)pid->parm); + + if (pid->eventcnt > 0) { + printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt); + printf("***LWP: Event id list:"); + for (i=0;i<pid->eventcnt;i++) + printf(" 0x%x", (int)pid->eventlist[i]); + putchar('\n'); + } + if (pid->wakevent>0) + printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent); +} + +static void +Dispatcher() /* Lightweight process dispatcher */ +{ + void *t; + int my_priority; + PROCESS old_cpptr; +#if 1 + int i = Highest_runnable_priority; + + Cal_Highest_runnable_priority(); + if (Highest_runnable_priority != i) + printf("hipri was %d actually %d\n", i, Highest_runnable_priority); + Highest_runnable_priority = i; +#endif + my_priority = lwp_cpptr->priority; + Debug(0, ("Dispatcher: %d runnable at pri %d hi %d blk %d", + runnable[my_priority].count, my_priority, + Highest_runnable_priority, PRE_Block)); + PRE_Block = 1; + if ((my_priority < Highest_runnable_priority) || + (runnable[my_priority].count > 0)) + { + Debug(0, ("Dispatcher: %s is now yielding", lwp_cpptr->name)); + /* I have to quit */ + old_cpptr = lwp_cpptr; + lwpinsert(old_cpptr, &runnable[my_priority]); + gettimeofday(&old_cpptr->lastReady, 0); + lwp_cpptr = runnable[Highest_runnable_priority].head; + + /* remove next process from runnable queue and signal it */ + lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]); + pthread_mutex_lock(&ct_mutex); + Debug(0, ("Dispatcher: %s going to signal %s condition\n", + old_cpptr->name, lwp_cpptr->name)) + + pthread_cond_signal(&lwp_cpptr->c); + + /* now sleep until somebody wakes me */ + Debug(0, ("Dispatcher: %s going to wait on own condition\n", + old_cpptr->name)) + pthread_cond_wait(&old_cpptr->c, &ct_mutex); + pthread_mutex_unlock(&ct_mutex); + + /* update global pointer */ + lwp_cpptr = old_cpptr; + } else { + Debug(0, ("Dispatcher: %s still running", lwp_cpptr->name)) + } + /* make sure HRP is set correct */ + Highest_runnable_priority = lwp_cpptr->priority; + if (lwp_cpptr->status == DESTROYED){ + /* the process was runnable but got destroyed by somebody */ + Free_PCB(lwp_cpptr); + Cal_Highest_runnable_priority(); + lwp_cpptr = runnable[Highest_runnable_priority].head; + lwpremove(lwp_cpptr, &runnable[Highest_runnable_priority]); + + pthread_mutex_lock(&ct_mutex); + pthread_cond_signal(&lwp_cpptr->c); + pthread_mutex_unlock(&ct_mutex); + pthread_exit(t); + } +#if 0 + if (PRE_Block != 1) Abort_LWP("PRE_Block not 1"); +#endif + PRE_Block = 0; +} + + +static void +Free_PCB(PROCESS pid) +{ + Debug(0, ("Entered Free_PCB")) + + if (pid->eventlist != NULL) free((char *)pid->eventlist); + free((char *)pid); +} + +static void +Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize, + void (*ep)(), char *parm, char *name) +{ + register int i = 0; + + Debug(0, ("Entered Initialize_PCB")) + if (name != NULL) + while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++; + temp -> name[31] = '\0'; + temp -> status = READY; + temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *)); + temp -> eventlistsize = EVINITSIZE; + temp -> eventcnt = 0; + temp -> wakevent = 0; + temp -> waitcnt = 0; + temp -> blockflag = 0; + temp -> iomgrRequest = 0; + temp -> priority = priority; + temp -> index = lwp_nextindex++; + temp -> ep = ep; + temp -> parm = parm; + temp -> misc = NULL; /* currently unused */ + temp -> next = NULL; + temp -> prev = NULL; + temp -> rused = 0; + temp -> level = 1; /* non-preemptable */ + timerclear(&temp->lastReady); + + /* initialize the mutex and condition */ + pthread_mutex_init(&temp->m, NULL); + pthread_cond_init(&temp->c, NULL); + + Debug(0, ("Leaving Initialize_PCB\n")) +} + +static int +Internal_Signal(register char *event) +{ + int rc = LWP_ENOWAIT; + register int i; + + Debug(0, ("Entered Internal_Signal [event id 0x%x]", (int)event)); + if (!lwp_init) return LWP_EINIT; + if (event == NULL) return LWP_EBADEVENT; + + for_all_elts(temp, blocked, { /* for all pcb's on the blocked q */ + if (temp->status == WAITING) + for (i=0; i < temp->eventcnt; i++) { /* check each event in list */ + if (temp -> eventlist[i] == event) { + temp -> eventlist[i] = NULL; + rc = LWP_SUCCESS; + Debug(0, ("decrementing %s to %d", temp->name, (temp->waitcnt-1))); + /* reduce waitcnt by 1 for the signal */ + /* if wcount reaches 0 then make the process runnable */ + if (--temp->waitcnt == 0) { + temp -> status = READY; + temp -> wakevent = i+1; + lwpmove(temp, &blocked, &runnable[temp->priority]); + gettimeofday(&temp->lastReady, 0); + Highest_runnable_priority = + MAX(Highest_runnable_priority, temp->priority); + Debug(0, ("marked runnable. hi_pri %d, %d at %d", Highest_runnable_priority, runnable[temp->priority].count, temp->priority)); + break; + } + } + } + }) + return rc; +} + +/* places the maximum of runnable task priorities in the global variable - + * Highest_runnable_priority. No runnable process is an error */ +static void +Cal_Highest_runnable_priority() +{ + int i; + for (i = LWP_MAX_PRIORITY; runnable[i].count == 0 && i >=0; i--); +#if 0 + if (i < 0) + Abort_LWP("No ready processes"); + else + Highest_runnable_priority = i; +#else + if (i >= 0) + Highest_runnable_priority = i; +#endif +} diff --git a/usr.sbin/afs/src/lwp/plwp.h b/usr.sbin/afs/src/lwp/plwp.h new file mode 100644 index 00000000000..4857eef176d --- /dev/null +++ b/usr.sbin/afs/src/lwp/plwp.h @@ -0,0 +1,191 @@ +/* $OpenBSD: plwp.h,v 1.1 1999/04/30 01:59:13 art Exp $ */ +#ifndef LWP_INCLUDED +#define LWP_INCLUDED + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_POSIX_SIGNALS +#define AFS_POSIX_SIGNALS 1 +#endif +#define AFS_LWP_MINSTACKSIZE (100 * 1024) +#include <sys/time.h> +#include <signal.h> + +#ifndef LWP_KERNEL +extern +#endif +char lwp_debug; /* ON = show LWP debugging trace */ + +extern int lwp_stackUseEnabled; +extern int lwp_MaxStackSeen; +#define LWP_ActiveProcess (lwp_cpptr+0) + +#define LWP_VERSION 210888001 + +#define LWP_SUCCESS 0 +#define LWP_EBADPID -1 +#define LWP_EBLOCKED -2 +#define LWP_EINIT -3 +#define LWP_EMAXPROC -4 +#define LWP_ENOBLOCK -5 +#define LWP_ENOMEM -6 +#define LWP_ENOPROCESS -7 +#define LWP_ENOWAIT -8 +#define LWP_EBADCOUNT -9 +#define LWP_EBADEVENT -10 +#define LWP_EBADPRI -11 +#define LWP_NO_STACK -12 +/* These two are for the signal mechanism. */ +#define LWP_EBADSIG -13 /* bad signal number */ +#define LWP_ESYSTEM -14 /* system call failed */ +/* These are for the rock mechanism */ +#define LWP_ENOROCKS -15 /* all rocks are in use */ +#define LWP_EBADROCK -16 /* the specified rock does not exist */ + + +/* Maximum priority permissible (minimum is always 0) */ +#define LWP_MAX_PRIORITY 4 + +/* Usual priority used by user LWPs */ +#define LWP_NORMAL_PRIORITY (LWP_MAX_PRIORITY-1) + +#define LWP_SignalProcess(event) LWP_INTERNALSIGNAL(event, 1) +#define LWP_NoYieldSignal(event) LWP_INTERNALSIGNAL(event, 0) + +/* Users aren't really supposed to know what a pcb is, but .....*/ +typedef struct lwp_pcb *PROCESS; + +/* Action to take on stack overflow. */ +#define LWP_SOQUIET 1 /* do nothing */ +#define LWP_SOABORT 2 /* abort the program */ +#define LWP_SOMESSAGE 3 /* print a message and be quiet */ +extern int lwp_overflowAction; + +/* Tells if stack size counting is enabled. */ +extern int lwp_stackUseEnabled; + +int LWP_QWait(void); +int LWP_QSignal(PROCESS); +int LWP_Init(int, int, PROCESS *); +int LWP_InitializeProcessSupport(int, PROCESS *); +int LWP_TerminateProcessSupport(); +int LWP_CreateProcess(void (*)(), int, int, char *, char *, PROCESS *); +int LWP_CurrentProcess(PROCESS *); +int LWP_DestroyProcess(PROCESS); +int LWP_DispatchProcess(); +int LWP_GetProcessPriority(PROCESS, int *); +int LWP_INTERNALSIGNAL(void *, int); +int LWP_WaitProcess(char *); +int LWP_MwaitProcess(int, char **); +int LWP_StackUsed(PROCESS, int *, int *); +int LWP_NewRock(int, char *); +int LWP_GetRock(int, char **); +char *LWP_Name(); +int LWP_Index(); +int LWP_HighestIndex(); + +int IOMGR_SoftSig(void (*)(), char *); +int IOMGR_Initialize(void); +int IOMGR_Finalize(void); +long IOMGR_Poll(void); +int IOMGR_Select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +int IOMGR_Cancel(register PROCESS); +int IOMGR_Signal(int, char *); +int IOMGR_CancelSignal(int); +void IOMGR_Sleep(unsigned int); + +int FT_Init(int, int); +#if __GNUC__ >= 2 +struct timezone; +#endif +int FT_GetTimeOfDay(register struct timeval *, register struct timezone *); +int TM_GetTimeOfDay(struct timeval *, struct timezone *); +int FT_AGetTimeOfDay(struct timeval *, struct timezone *); +unsigned int FT_ApproxTime(void); + +#include <pthread.h> + +/* Initial size of eventlist in a PCB; grows dynamically */ +#define EVINITSIZE 5 + +struct rock + {/* to hide things associated with this LWP under */ + int tag; /* unique identifier for this rock */ + pthread_key_t val; + /*char *value;*/ /* pointer to some arbitrary data structure */ + }; + +#define MAXROCKS 4 /* max no. of rocks per LWP */ + +struct lwp_pcb { /* process control block */ + char name[32]; + int rc; + char status; + char **eventlist; + char eventlistsize; + int eventcnt; + int wakevent; + int waitcnt; + char blockflag; + int priority; + PROCESS misc; + char *stack; + int stacksize; + long stackcheck; + void (*ep)(char *); + char *parm; + int rused; + struct rock rlist[MAXROCKS]; + PROCESS next, prev; + int level; + struct IoRequest *iomgrRequest; + int index; + struct timeval lastReady; + pthread_mutex_t m; + pthread_cond_t c; + pthread_attr_t a; +}; + +extern int lwp_nextindex; /* Next lwp index to assign */ + +extern PROCESS lwp_cpptr; /* pointer to current process pcb */ +struct lwp_ctl { /* LWP control structure */ + int processcnt; /* number of lightweight processes */ + char *outersp; /* outermost stack pointer */ + PROCESS outerpid; /* process carved by Initialize */ + PROCESS first, last; /* ptrs to first and last pcbs */ + char dsptchstack[800]; /* stack for dispatcher use only */ +}; + +extern char PRE_Block; /* used in preemption control (in preempt.c) */ + +/* Debugging macro */ +#ifdef LWPDEBUG +#define lwpdebug(level, msg)\ + if (lwp_debug > level) {\ + printf("***LWP (0x%x): ", lwp_cpptr);\ + printf msg;\ + putchar('\n');\ + fflush(stdout);\ + } +#else /* LWPDEBUG */ +#define lwpdebug(level, msg) +#endif /* LWPDEBUG */ + +#define MAXTHREADS 100 + +#endif /* LWP_INCLUDED */ + + + diff --git a/usr.sbin/afs/src/lwp/process-vpp.s b/usr.sbin/afs/src/lwp/process-vpp.s new file mode 100644 index 00000000000..707f7c855b5 --- /dev/null +++ b/usr.sbin/afs/src/lwp/process-vpp.s @@ -0,0 +1,171 @@ +/* -*- text -*- */ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: process-vpp.s,v 1.1 1999/04/30 01:59:14 art Exp $ */ + +/* LWP context switch for Fujitsu UXP/V */ + +#define registers 8 /* leave room for fp, and ra */ +#define floats (registers + 12 * 4) +#ifdef SAVE_FLOATS +#define FRAMESIZE (floats + 15 * 8) +#else +#define FRAMESIZE floats +#endif + +/* +void savecontext(int (*)(void), struct savearea*, void*); +*/ + + .section .text + .global savecontext + .align 8 +savecontext: + /* make space */ + or %gr1, %gr0, %gr2 & st %gr2, %gr1, 4 + addi23 %gr1, -FRAMESIZE, %gr1 & st %gr3, %gr2, %gr0 + + /* save registers */ + /* XXX save more registers? */ + st %gr4, %gr1, registers + 0 + st %gr5, %gr1, registers + 4 + st %gr6, %gr1, registers + 8 + st %gr7, %gr1, registers + 12 + st %gr8, %gr1, registers + 16 + st %gr9, %gr1, registers + 20 + st %gr10, %gr1, registers + 24 + st %gr11, %gr1, registers + 28 + st %gr12, %gr1, registers + 32 + st %gr13, %gr1, registers + 36 + st %gr14, %gr1, registers + 40 + st %gr15, %gr1, registers + 44 + +#ifdef SAVE_FLOATS + /* save floting point registers */ + st.d %fr1, %gr1, floats + 0 + st.d %fr2, %gr1, floats + 8 + st.d %fr3, %gr1, floats + 16 + st.d %fr4, %gr1, floats + 24 + st.d %fr5, %gr1, floats + 32 + st.d %fr6, %gr1, floats + 40 + st.d %fr7, %gr1, floats + 48 + st.d %fr8, %gr1, floats + 56 + st.d %fr9, %gr1, floats + 64 + st.d %fr10, %gr1, floats + 72 + st.d %fr11, %gr1, floats + 80 + st.d %fr12, %gr1, floats + 88 + st.d %fr13, %gr1, floats + 96 + st.d %fr14, %gr1, floats + 104 + st.d %fr15, %gr1, floats + 112 +#endif + + /* block */ + addi5 %gr0, 1, %gr20 + seti PRE_Block, %gr21 + st.c %gr20, %gr21, 0 + + /* save sp */ + st %gr1, %gr17, 0 + /* new sp */ + subi5 %gr18, 0, %gr0 + brc %iccp.z, samestack + + /* switch to new stack */ + or %gr18, %gr0, %gr1 + /* load fp */ + ld %gr1, 0, %gr2 + +samestack: + /* is this necessary? */ + or %gr16, %gr0, %gr3 + jmp %gr3 + + .type savecontext,@function + .size savecontext,.-savecontext + +/* +void returnto(struct savearea*); +*/ + .global returnto + .align 8 +returnto: + seti PRE_Block, %gr17 + st.c %gr0, %gr17, 0 + /* restore sp */ + ld %gr16, 0, %gr1 + /* restore registers */ + ld %gr1, registers + 0, %gr4 + ld %gr1, registers + 4, %gr5 + ld %gr1, registers + 8, %gr6 + ld %gr1, registers + 12, %gr7 + ld %gr1, registers + 16, %gr8 + ld %gr1, registers + 20, %gr9 + ld %gr1, registers + 24, %gr10 + ld %gr1, registers + 28, %gr11 + ld %gr1, registers + 32, %gr12 + ld %gr1, registers + 36, %gr13 + ld %gr1, registers + 40, %gr14 + ld %gr1, registers + 44, %gr15 + +#ifdef SAVE_FLOATS + /* restore floting point registers */ + ld.d %gr1, floats + 0, %fr1 + ld.d %gr1, floats + 8, %fr2 + ld.d %gr1, floats + 16, %fr3 + ld.d %gr1, floats + 24, %fr4 + ld.d %gr1, floats + 32, %fr5 + ld.d %gr1, floats + 40, %fr6 + ld.d %gr1, floats + 48, %fr7 + ld.d %gr1, floats + 56, %fr8 + ld.d %gr1, floats + 64, %fr9 + ld.d %gr1, floats + 72, %fr10 + ld.d %gr1, floats + 80, %fr11 + ld.d %gr1, floats + 88, %fr12 + ld.d %gr1, floats + 96, %fr13 + ld.d %gr1, floats + 104, %fr14 + ld.d %gr1, floats + 112, %fr15 +#endif + addi23 %gr1, FRAMESIZE, %gr1 + ld %gr1, 0, %gr3 + ld %gr1, 4, %gr2 + + jmp %gr3 + + .type returnto,@function + .size returnto,.-returnto diff --git a/usr.sbin/afs/src/lwp/rw.c b/usr.sbin/afs/src/lwp/rw.c new file mode 100644 index 00000000000..96e19d15e02 --- /dev/null +++ b/usr.sbin/afs/src/lwp/rw.c @@ -0,0 +1,255 @@ +/* $OpenBSD: rw.c,v 1.1 1999/04/30 01:59:14 art Exp $ */ +/* +**************************************************************************** +* Copyright IBM Corporation 1988, 1989 - All Rights Reserved * +* * +* Permission to use, copy, modify, and distribute this software and its * +* documentation for any purpose and without fee is hereby granted, * +* provided that the above copyright notice appear in all copies and * +* that both that copyright notice and this permission notice appear in * +* supporting documentation, and that the name of IBM not be used in * +* advertising or publicity pertaining to distribution of the software * +* without specific, written prior permission. * +* * +* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM * +* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY * +* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * +* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * +* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * +**************************************************************************** +*/ + +/* + (Multiple) readers & writers test of LWP stuff. + +Created: 11/1/83, J. Rosenberg + +*/ + +#include <sys/time.h> +#include <stdio.h> +#include <stdlib.h> + +#include <lwp.h> +#include "lock.h" +#include "preempt.h" + +#define DEFAULT_READERS 5 + +#define STACK_SIZE (16*1024) + +/* The shared queue */ +typedef struct QUEUE { + struct QUEUE *prev, *next; + char *data; + struct Lock lock; +} queue; + +queue *init() +{ + queue *q; + + q = (queue *) malloc(sizeof(queue)); + q -> prev = q -> next = q; + return(q); +} + +char empty(queue *q) +{ + return (q->prev == q && q->next == q); +} + +void insert(queue *q, char *s) +{ + queue *new; + + new = (queue *) malloc(sizeof(queue)); + new -> data = s; + new -> prev = q -> prev; + q -> prev -> next = new; + q -> prev = new; + new -> next = q; +} + +char *Remove(queue *q) +{ + queue *old; + char *s; + + if (empty(q)) { + printf("Remove from empty queue"); + abort(); + } + + old = q -> next; + q -> next = old -> next; + q -> next -> prev = q; + s = old -> data; + free(old); + return(s); +} + +queue *q; + +int asleep; /* Number of processes sleeping -- used for + clean termination */ + +static int read_process(int id) +{ + int foo; + printf("\t[Reader %d]\n", id); + LWP_NewRock(1, id); + LWP_DispatchProcess(); /* Just relinquish control for now */ + + PRE_PreemptMe(); + for (;;) { + register int i; + + /* Wait until there is something in the queue */ + asleep++; + ObtainReadLock(&q->lock); + while (empty(q)) { + ReleaseReadLock(&q->lock); + LWP_WaitProcess((void *)q); + ObtainReadLock(&q->lock); + } + asleep--; + for (i=0; i<10000; i++) ; + PRE_BeginCritical(); + LWP_GetRock(1, &foo); + printf("[%d: %s]\n", foo, Remove(q)); + PRE_EndCritical(); + ReleaseReadLock(&q->lock); + LWP_DispatchProcess(); + } +} + +static void write_process() +{ + static char *messages[] = + { + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + "Mary had a little lamb,", + "Its fleece was white as snow,", + "And everywhere that Mary went,", + "The lamb was sure to go", + 0 + }; + char **mesg; + + printf("\t[Writer]\n"); + PRE_PreemptMe(); + + /* Now loop & write data */ + for (mesg=messages; *mesg!=0; mesg++) { + ObtainWriteLock(&q->lock); + insert(q, *mesg); + ReleaseWriteLock(&q->lock); + LWP_SignalProcess(q); + } + + asleep++; +} + +/* + Arguments: + 0: Unix junk, ignore + 1: Number of readers to create (default is DEFAULT_READERS) + 2: # msecs for interrupt (to satisfy Larry) + 3: Present if lwp_debug to be set +*/ + + +int +main(int argc, char **argv) +{ + int nreaders, i; + long interval; /* To satisfy Brad */ + PROCESS *readers; + PROCESS writer, master; + struct timeval tv; + char rname[9]; + + printf("\n*Readers & Writers*\n\n"); + setbuf(stdout, 0); + + /* Determine # readers */ + if (argc == 1) + nreaders = DEFAULT_READERS; + else + sscanf(*++argv, "%d", &nreaders); + printf("[There will be %d readers]\n", nreaders); + + interval = (argc >= 3 ? atoi(*++argv)*1000 : 50000); + + if (argc == 4) lwp_debug = 1; + LWP_InitializeProcessSupport(0, &master); + printf("[Support initialized]\n"); + tv.tv_sec = 0; + tv.tv_usec = interval; + PRE_InitPreempt(&tv); + + /* Initialize queue */ + q = init(); + + /* Initialize lock */ + Lock_Init(&q->lock); + + asleep = 0; + /* Now create readers */ + printf("[Creating Readers...\n"); + readers = (PROCESS *) calloc(nreaders, sizeof(PROCESS)); + for (i=0; i<nreaders; i++) { + sprintf(rname, "Reader %d", i); + LWP_CreateProcess((void *)(read_process), STACK_SIZE, 0, (char *)i, + rname, &readers[i]); + } + printf("done]\n"); + + printf("\t[Creating Writer...\n"); + LWP_CreateProcess(write_process, STACK_SIZE, 1, 0, "Writer", &writer); + printf("done]\n"); + + /* Now loop until everyone's done */ + while (asleep != nreaders+1) LWP_DispatchProcess(); + /* Destroy the readers */ + for (i=nreaders-1; i>=0; i--) LWP_DestroyProcess(readers[i]); + printf("\n*Exiting*\n"); + return 0; +} diff --git a/usr.sbin/afs/src/rx/rx-new.h b/usr.sbin/afs/src/rx/rx-new.h new file mode 100644 index 00000000000..f335e7a0fe4 --- /dev/null +++ b/usr.sbin/afs/src/rx/rx-new.h @@ -0,0 +1,239 @@ +/* $OpenBSD: rx-new.h,v 1.1 1999/04/30 01:59:14 art Exp $ */ +/* + * rx.h,v 1.7 1995/04/11 06:07:07 assar Exp + */ + +#ifndef _RX_ +#define _RX_ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <list.h> +#include <pthread.h> +#include <thrpool.h> + +#include <rx_pkt.h> + +/* XXX - This should be moved somewhere else and replaced with XDR */ + +typedef u_long unsigned32; +typedef u_short unsigned16; + +/* Security garbage */ + +typedef struct rx_securityClass { +} rx_securityClass; + +typedef struct rx_connection rx_connection; + +typedef struct rx_call rx_call; + +typedef struct rx_service rx_service; + +#define RX_MAXDATA 1444 /* XXX - ??? */ + + +typedef struct rx_wirepacket { + rx_header header; + char data[RX_MAXDATA]; +} rx_wirepacket; + +/* + * There are two different types of acks. + * soft ack means that the packet has been receieved at the other end, + * but the sender should not throw away the packet yet. The receiver + * can still drop the packet or not give it to the application. + * The point of the soft acks is mainly flow-control. + * + * A hard ack means that the packet has been acknowledged by the + * application. Then the packet can be thrown away. + * + */ + +typedef enum { + RX_PKT_SOFT_ACK = 1 +} rx_packet_flags; + +typedef struct rx_packet { + rx_wirepacket wire; + unsigned datalen; + rx_call *call; + rx_packet_flags flags; +} rx_packet; + + +/* every call - i.e. RPC transaction */ + +struct rx_call { + enum { SENDING, RECEIVING } mode; + u_long callno; /* Call # of this connection */ + u_long seqno; /* Seq # for packets */ + int channelid; /* What channel are we using? */ + rx_connection *conn; + List *recvpackets; /* List of received packets */ +#if 0 + List *ooopackets; /* Packets rec'd out-of-order */ +#endif + rx_packet *thispacket; /* This packet, sending or receiving */ + char *ptr; /* Here we should write data */ + unsigned nleft; /* How much data there is left */ + pthread_mutex_t mutex; /* Synchronisation */ + pthread_cond_t cond; +}; + +/* This represents the on-going communication, i.e. a connection */ + +typedef enum { + RX_CONN_SERVER, /* This is a server */ + RX_CONN_CLIENT /* The other side is a server */ +} rx_connection_type; + +#define RX_WINDOW 15 + +struct rx_connection { + time_t epoch; /* Time when this connection started */ + u_long connid; /* Connection ID. How? */ + struct sockaddr_in peer; /* The one we're talking to */ + u_long serialno; /* Next serial number to use */ + u_long callno[MAXCALLS]; /* Next call number to use */ + rx_call *calls[MAXCALLS]; /* The on-going calls */ + u_char secindex; /* Security index */ + u_short serviceid; /* Service ID */ + rx_connection_type type; /* Type of connection C-S or S-C */ + u_long maxnoacked; /* Max packet sent and soft-acked */ + List *packets; /* Not yet acked sent packets */ + u_long window; /* Size of the window */ + pthread_cond_t condsend; /* Conditional variable for sending */ + pthread_mutex_t mutexsend; /* Mutex for above */ + pthread_cond_t condrecv; + pthread_mutex_t mutexrecv; + rx_service *service; /* Service if server, else NULL */ +}; + +/* + * About packets: + * + * Here we keep the packets that have been sent but not yet + * hard-acked. When a packet has been soft-acked we set a flag in the + * packet_flags and stop the resend-timer. + */ + +struct rx_service { + u_short port; + u_short serviceid; + char *servicename; + int (*serviceproc)(rx_call *); + Thrpool *thrpool; +}; + +/* functions */ + +int rx_Init (int port); + +rx_connection *rx_NewConnection (struct in_addr host, u_short port, + u_short service, + rx_securityClass *sec, + int secindex); + +void rx_DestroyConnection (rx_connection *); + +rx_call *rx_NewCall (rx_connection *); + +int rx_EndCall (rx_call *, int); + +rx_service *rx_NewService(u_short port, u_short serviceid, + char *servicename, rx_securityClass **so, + int nso, int (*serviceproc)(rx_call *)); + +int rx_Write (rx_call *, void *, int); +int rx_Read (rx_call *, void *, int); +int rx_FlushWrite (rx_call *call); + + +#endif /* _RX_ */ + + + + +/* Old garbage */ + +#if 0 + +/* header of a RPC packet */ +/* We should use XDR on this too. */ + +typedef enum { + HT_DATA = 1, + HT_ACK = 2, + HT_BUSY = 3, + HT_ABORT = 4, + HT_ACKALL = 5, + HT_CHAL = 6, + HT_RESP = 7, + HT_DEBUG = 8 +} rx_header_type; + +/* For flags in header */ + +enum { + HF_CLIENT_INITIATED = 1, + HF_REQ_ACK = 2, + HF_LAST = 4, + HF_MORE = 8}; + +#define MAXCALLS 4 + +#define CALL_MASK (MAXCALLS-1) +#define CONNID_MASK (~(MAXCALLS-1)) + +typedef struct rx_header { + unsigned32 epoch; + unsigned32 connid; /* And channel ID */ + unsigned32 callid; + unsigned32 seqno; /* Call-based number */ + unsigned32 serialno; /* Unique number */ + u_char type; + u_char flags; + u_char status; + u_char secindex; + unsigned16 reserved; /* ??? verifier? */ + unsigned16 serviceid; +/* This should be the other way around according to everything but */ +/* tcpdump */ +} rx_header; + +#endif + +#if 0 + +typedef enum { + RX_ACK_REQUESTED = 1, + RX_ACK_DUPLICATE = 2, + RX_ACK_OUT_OF_SEQUENCE = 3, + RX_ACK_EXEEDS_WINDOW = 4, + RX_ACK_NOSPACE = 5, + RX_ACK_PING = 6, + RX_ACK_PING_RESPONSE = 7, + RX_ACK_DELAY = 8 +} rx_ack_reason; + +typedef enum { + RX_ACK_TYPE_NACK = 0, + RX_ACK_TYPE_ACK = 1 +} rx_ack_type; + +#define RXMAXACKS 255 + +typedef struct rx_ack_packet { + unsigned16 bufferspace; + unsigned16 maxskew; + unsigned32 firstpacket; /* First packet in acks below */ + unsigned32 prevpacket; + unsigned32 serial; /* Packet that prompted this one */ + u_char reason; /* rx_ack_reason */ + u_char nacks; /* # of acks */ + u_char acks[RXMAXACKS]; /* acks (rx_ack_type) */ +} rx_ack_packet; + +#endif diff --git a/usr.sbin/afs/src/rx/rxgencon.h b/usr.sbin/afs/src/rx/rxgencon.h new file mode 100644 index 00000000000..19bed98dc2b --- /dev/null +++ b/usr.sbin/afs/src/rx/rxgencon.h @@ -0,0 +1,39 @@ +/* $OpenBSD: rxgencon.h,v 1.1 1999/04/30 01:59:15 art Exp $ */ +/* +**************************************************************************** +* Copyright IBM Corporation 1988, 1989 - All Rights Reserved * +* * +* Permission to use, copy, modify, and distribute this software and its * +* documentation for any purpose and without fee is hereby granted, * +* provided that the above copyright notice appear in all copies and * +* that both that copyright notice and this permission notice appear in * +* supporting documentation, and that the name of IBM not be used in * +* advertising or publicity pertaining to distribution of the software * +* without specific, written prior permission. * +* * +* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM * +* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY * +* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * +* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * +* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * +**************************************************************************** +*/ + +/* $KTH: rxgencon.h,v 1.1 1999/02/05 06:09:06 lha Exp $ */ + +#ifndef _RXGEN_CONSTS_ +#define _RXGEN_CONSTS_ + +/* These are some rxgen-based (really arbitrary) error codes... */ +#define RXGEN_SUCCESS 0 +#define RXGEN_CC_MARSHAL -450 +#define RXGEN_CC_UNMARSHAL -451 +#define RXGEN_SS_MARSHAL -452 +#define RXGEN_SS_UNMARSHAL -453 +#define RXGEN_DECODE -454 +#define RXGEN_OPCODE -455 +#define RXGEN_SS_XDRFREE -456 +#define RXGEN_CC_XDRFREE -457 + +#endif /* _RXGEN_CONSTS_ */ diff --git a/usr.sbin/afs/src/rxdef/rx_pkt.xg b/usr.sbin/afs/src/rxdef/rx_pkt.xg new file mode 100644 index 00000000000..ce5743aa1f2 --- /dev/null +++ b/usr.sbin/afs/src/rxdef/rx_pkt.xg @@ -0,0 +1,77 @@ +/* rx_pkt.xg,v 1.3 1994/12/27 03:37:04 assar Exp */ + +/* header of a RPC packet */ + +enum rx_header_type { + HT_DATA = 1, + HT_ACK = 2, + HT_BUSY = 3, + HT_ABORT = 4, + HT_ACKALL = 5, + HT_CHAL = 6, + HT_RESP = 7, + HT_DEBUG = 8 +}; + +/* For flags in header */ + +enum rx_header_flag { + HF_CLIENT_INITIATED = 1, + HF_REQ_ACK = 2, + HF_LAST = 4, + HF_MORE = 8 +}; + +%#define MAXCALLS 4 + +%#define CALL_MASK (MAXCALLS-1) +%#define CONNID_MASK (~(MAXCALLS-1)) + +const RX_HEADER_SIZE=28; + +struct rx_header { + unsigned epoch; + unsigned connid; /* And channel ID */ + unsigned callid; + unsigned seqno; + unsigned serialno; + u_char type; + u_char flags; + u_char status; + u_char secindex; + u_short reserved; /* ??? verifier? */ + u_short serviceid; +/* This should be the other way around according to everything but */ +/* tcpdump */ +}; + +enum rx_ack_reason { + RX_ACK_REQUESTED = 1, + RX_ACK_DUPLICATE = 2, + RX_ACK_OUT_OF_SEQUENCE = 3, + RX_ACK_EXEEDS_WINDOW = 4, + RX_ACK_NOSPACE = 5, + RX_ACK_PING = 6, + RX_ACK_PING_RESPONSE = 7, + RX_ACK_DELAY = 8 +}; + +enum rx_ack_type { + RX_ACK_TYPE_NACK = 0, + RX_ACK_TYPE_ACK = 1 +}; + +const RXMAXACKS=255; + +struct rx_ack_header { + u_short bufferspace; /* # of packet buffers available */ + u_short maxskew; + u_long firstpacket; /* First packet in acks below */ + u_long prevpacket; + u_long serial; /* Packet that prompted this one */ + u_char reason; /* rx_ack_reason */ +/* u_char nacks;*/ /* # of acks */ + u_char acks<u_char>; +/* u_char acks[RXMAXACKS];*/ /* acks (rx_ack_type) */ +}; + diff --git a/usr.sbin/afs/src/util/heap.c b/usr.sbin/afs/src/util/heap.c new file mode 100644 index 00000000000..959c0c42ed1 --- /dev/null +++ b/usr.sbin/afs/src/util/heap.c @@ -0,0 +1,295 @@ +/* $OpenBSD: heap.c,v 1.1 1999/04/30 01:59:17 art Exp $ */ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Heap + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$KTH: heap.c,v 1.1 1998/12/28 00:14:40 assar Exp $"); +#endif + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include "heap.h" + +/* + * Allocate a new heap of size `sz' with compare function `cmp'. + */ + +Heap * +heap_new (unsigned sz, heap_cmp_fn cmp) +{ + Heap *ret; + int i; + + ret = malloc (sizeof(*ret)); + if (ret == NULL) + return ret; + + ret->cmp = cmp; + ret->max_sz = sz; + ret->sz = 0; + ret->data = malloc (sz * sizeof(*ret->data)); + if (ret->data == NULL) { + free (ret); + return NULL; + } + for (i = 0; i < sz; ++i) { + ret->data[i].data = NULL; + ret->data[i].ptr = NULL; + } + return ret; +} + +static inline unsigned +parent (unsigned n) +{ + return (n + 1) / 2 - 1; +} + +static inline unsigned +left_child (unsigned n) +{ + return 2 * n + 1; +} + +static inline unsigned +right_child (unsigned n) +{ + return 2 * n + 2; +} + +static heap_ptr dummy; + +/* + * + */ + +static void +assign (Heap *h, unsigned n, heap_element el) +{ + h->data[n] = el; + *(h->data[n].ptr) = n; +} + +/* + * + */ + +static void +upheap (Heap *h, unsigned n) +{ + heap_element v = h->data[n]; + + while (n > 0 && (*h->cmp)(h->data[parent(n)].data, v.data) > 0) { + assign (h, n, h->data[parent(n)]); + n = parent(n); + } + assign (h, n, v); +} + +/* + * + */ + +static void +downheap (Heap *h, unsigned n) +{ + heap_element v = h->data[n]; + + while (n < h->sz / 2) { + int cmp1, cmp2; + unsigned new_n; + + assert (left_child(n) < h->sz); + + new_n = left_child(n); + + cmp1 = (*h->cmp)(v.data, h->data[new_n].data); + + if (right_child(n) < h->sz) { + cmp2 = (*h->cmp)(v.data, h->data[right_child(n)].data); + if (cmp2 > cmp1) { + cmp1 = cmp2; + new_n = right_child(n); + } + } + + if (cmp1 > 0) { + assign (h, n, h->data[new_n]); + n = new_n; + } else { + break; + } + } + assign (h, n, v); +} + +/* + * Insert a new element `data' into `h'. + * Return 0 if succesful or else -1. + */ + +int +heap_insert (Heap *h, const void *data, heap_ptr *ptr) +{ + assert (data != NULL); + + if (h->sz == h->max_sz) { + unsigned new_sz = h->max_sz * 2; + heap_element *tmp; + + tmp = realloc (h->data, new_sz * sizeof(*h->data)); + if (tmp == NULL) + return -1; + h->max_sz = new_sz; + h->data = tmp; + } + if (ptr == NULL) + ptr = &dummy; + + h->data[h->sz].data = data; + h->data[h->sz].ptr = ptr; + upheap (h, h->sz); + ++h->sz; + return 0; +} + +/* + * Return the head of the heap `h' (or NULL if it's empty). + */ + +const void * +heap_head (Heap *h) +{ + if (h->sz == 0) + return NULL; + else + return h->data[0].data; +} + +/* + * Remove element `n' from the heap `h' + */ + +static void +remove_this (Heap *h, unsigned n) +{ + assert (n < h->sz); + + --h->sz; + h->data[n] = h->data[h->sz]; + h->data[h->sz].data = NULL; + h->data[h->sz].ptr = NULL; + if (n != h->sz) { + downheap (h, n); + upheap (h, n); + } +} + +/* + * Remove the head from the heap `h'. + */ + +void +heap_remove_head (Heap *h) +{ + remove_this (h, 0); +} + +/* + * Remove this very element from the heap `h'. + * Return 0 if succesful and -1 if it couldn't be found. + */ + +int +heap_remove (Heap *h, heap_ptr ptr) +{ + if (h->sz == 0) + return -1; + + remove_this (h, ptr); + return 0; +} + +/* + * Delete the heap `h' + */ + +void +heap_delete (Heap *h) +{ + free (h->data); + free (h); +} + +/* + * + */ + +static Bool +do_verify (Heap *h, unsigned n) +{ + if (left_child(n) < h->sz) { + if((*h->cmp)(h->data[n].data, h->data[left_child(n)].data) > 0) + return FALSE; + if (!do_verify (h, left_child(n))) + return FALSE; + } + if (right_child(n) < h->sz) { + if((*h->cmp)(h->data[n].data, h->data[right_child(n)].data) > 0) + return FALSE; + if (!do_verify (h, right_child(n))) + return FALSE; + } + return TRUE; +} + +/* + * Verify that `h' is really a heap. + */ + +Bool +heap_verify (Heap *h) +{ + return do_verify (h, 0); +} diff --git a/usr.sbin/afs/src/util/heap.h b/usr.sbin/afs/src/util/heap.h new file mode 100644 index 00000000000..d13bb1a30d1 --- /dev/null +++ b/usr.sbin/afs/src/util/heap.h @@ -0,0 +1,91 @@ +/* $OpenBSD: heap.h,v 1.1 1999/04/30 01:59:17 art Exp $ */ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * an abstract heap implementation + */ + +/* $KTH: heap.h,v 1.1 1998/12/28 00:14:41 assar Exp $ */ + +#ifndef _HEAP_ +#define _HEAP_ + +#include "bool.h" + +typedef int (*heap_cmp_fn)(const void *, const void *); + +typedef unsigned heap_ptr; + +struct heap_element { + const void *data; + heap_ptr *ptr; +}; + +typedef struct heap_element heap_element; + +struct heap { + heap_cmp_fn cmp; + unsigned max_sz; + unsigned sz; + heap_element *data; +}; + +typedef struct heap Heap; + +Heap *heap_new (unsigned sz, heap_cmp_fn cmp); + +int +heap_insert (Heap *h, const void *data, heap_ptr *ptr); + +const void * +heap_head (Heap *h); + +void +heap_remove_head (Heap *h); + +int +heap_remove (Heap *h, heap_ptr ptr); + +void +heap_delete (Heap *h); + +Bool +heap_verify (Heap *h); + +#endif /* _HEAP_ */ diff --git a/usr.sbin/afs/src/util/heaptest.c b/usr.sbin/afs/src/util/heaptest.c new file mode 100644 index 00000000000..ff0e5164eb3 --- /dev/null +++ b/usr.sbin/afs/src/util/heaptest.c @@ -0,0 +1,120 @@ +/* $OpenBSD: heaptest.c,v 1.1 1999/04/30 01:59:17 art Exp $ */ +/* + * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +RCSID("$KTH: heaptest.c,v 1.2 1999/02/13 05:03:25 assar Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <err.h> +#include "heap.h" + +struct foo { + int i; + heap_ptr hptr; +}; + +static int +cmp(const void *v1, const void *v2) +{ + const struct foo *foo1 = (const struct foo *)v1; + const struct foo *foo2 = (const struct foo *)v2; + + return foo1->i - foo2->i; +} + +static int +testit (unsigned n) +{ + struct foo *foos, *bars; + Heap *h1, *h2; + int i; + + foos = malloc (n * sizeof(*foos)); + bars = malloc (n * sizeof(*bars)); + assert (foos != NULL && bars != NULL); + h1 = heap_new (n, cmp); + h2 = heap_new (n, cmp); + assert (h1 != NULL && h2 != NULL); + for (i = 0; i < n; ++i) { + foos[i].i = bars[i].i = rand(); + heap_insert (h1, (void *)&foos[i], NULL); + heap_insert (h2, (void *)&foos[i], &foos[i].hptr); + if (!heap_verify(h1) || !heap_verify(h2)) + abort (); + } + for (i = 0; i < n; ++i) { + heap_remove (h2, foos[i].hptr); + if (!heap_verify(h2)) + abort (); + } + qsort (bars, n, sizeof(*bars), cmp); + for (i = 0; i < n; ++i) { + struct foo *f = (struct foo *)heap_head (h1); + + if (bars[i].i != f->i) + abort (); + heap_remove_head (h1); + if (!heap_verify(h1)) + abort (); + } + heap_delete (h1); + heap_delete (h2); + free (foos); + free (bars); + return 0; +} + +int +main(int argc, char **argv) +{ + int i, n; + + if (argc != 2) + errx (1, "argc != 2"); + + n = atoi (argv[1]); + for (i = 0; i < n; ++i) + testit (rand () % 1000); + return 0; +} |