static int ioctl_set_pvc(ITF *itf,uint32_t ip,struct sockaddr_atmpvc *addr, const struct atm_qos *qos,int sndbuf,int flags) { ENTRY *entry; VCC *vcc; int fd,result; if (lookup_ip(itf,ip)) return -EEXIST; if ((fd = connect_vcc((struct sockaddr *) addr,qos,sndbuf,0)) < 0) return fd; if ((result = set_ip(fd,ip)) < 0) { do_close(fd); return result; } if (flags & ATF_NULL) { if ((result = set_encap(fd,0)) < 0) return result; flags |= ATF_PERM; } entry = alloc_entry(0); entry->state = as_valid; entry->ip = ip; entry->qos = *qos; entry->sndbuf = sndbuf; entry->flags = flags; entry->itf = itf; vcc = alloc_t(VCC); vcc->active = 1; vcc->connecting = 0; vcc->fd = fd; vcc->entry = entry; if (!(flags & ATF_PERM)) START_TIMER(entry,CREVAL); Q_INSERT_HEAD(entry->vccs,vcc); Q_INSERT_HEAD(itf->table,entry); return 0; }
static int ioctl_set_svc(ITF *itf,uint32_t ip,struct sockaddr_atmsvc *addr, const struct atm_qos *qos,int sndbuf,int flags) { ENTRY *entry; if (flags & ATF_ARPSRV) flags |= ATF_PERM; if (lookup_ip(itf,ip)) return -EEXIST; entry = alloc_entry(1); entry->state = as_valid; entry->ip = ip; entry->addr = alloc_t(struct sockaddr_atmsvc); *entry->addr = *addr; entry->qos = *qos; entry->sndbuf = sndbuf; entry->flags = flags; if (!(flags & ATF_PERM) || (flags & ATF_ARPSRV)) { if (itf->arp_srv) START_TIMER(entry,CREVAL); else START_TIMER(entry,SREVAL); } entry->itf = itf; Q_INSERT_HEAD(itf->table,entry); if (!(flags & ATF_ARPSRV)) return 0; entry->state = as_invalid; itf->arp_srv = entry; (void) want_arp_srv(itf); return 0; }
static int resolve(ITF *itf,uint32_t ip,ENTRY **entry,int want_vc) { *entry = lookup_ip(itf,ip); if ((!*entry || (*entry)->state != as_valid) && !itf->arp_srv) return -1; /* bad luck - no ARP server when we need one */ if (*entry) { if (want_vc) (*entry)->flags &= ~ATF_NOVC; switch ((*entry)->state) { case as_resolv: return 1; /* somebody else is already taking care of that */ case as_valid: if (!(*entry)->vccs && !((*entry)->flags & ATF_NOVC)) connect_me(*entry); return 0; case as_invalid: if ((*entry)->svc && (*entry)->itf && (*entry)->itf->arp_srv && !((*entry)->flags & ATF_ARPSRV)) break; return -1; default: diag(COMPONENT,DIAG_FATAL,"bad state %d",(*entry)->state); } } else { *entry = alloc_entry(1); (*entry)->flags = ATF_PUBL | (want_vc ? 0 : ATF_NOVC); (*entry)->ip = ip; (*entry)->itf = itf; Q_INSERT_HEAD(itf->table,*entry); (*entry)->qos = itf->qos; } revalidate(*entry); return 1; }
static int cr_newsymlink(nameset_entry_t parent) { int weight = (*cr_l_weights)(); struct cr_rec *l; if ((l = malloc(sizeof(struct cr_rec))) == NULL) { report_perror(FATAL, "malloc error"); return -1; } bzero(l, sizeof(struct cr_rec)); if ((l->nse = nameset_alloc(parent, NFLNK, weight)) == NULL) { report_error(FATAL, "nameset_alloc error"); free(l); return -1; } if (nameset_getfname(l->nse, l->name, sizeof(l->name)) < 0) { report_error(FATAL, "nameset_getfname error"); free(l); return -1; } l->parent_nse = parent; Q_INSERT_HEAD(&cr_worklist, l, link); return 0; }
static int cr_newfile(nameset_entry_t parent) { int weight = (*cr_f_weights)(); struct cr_rec *f; if ((f = malloc(sizeof(struct cr_rec))) == NULL) { report_perror(FATAL, "malloc error"); return -1; } bzero(f, sizeof(struct cr_rec)); if ((f->nse = nameset_alloc(parent, NFREG, weight)) == NULL) { report_error(FATAL, "nameset_alloc error"); free(f); return -1; } if (nameset_getfname(f->nse, f->name, sizeof(f->name)) < 0) { report_error(FATAL, "nameset_getfname error"); free(f); return -1; } f->parent_nse = parent; f->size = (*cr_f_sizes)(); f->nse->size = f->size; /* eventually */ Q_INSERT_HEAD(&cr_worklist, f, link); return 0; }
static void cr_symlink_callback(void *arg, struct nfsmsg *reply, u_int32_t xid) { struct cr_rec *l = (struct cr_rec *)arg; struct symlink_res *res = reply ? &reply->u.symlink_res : NULL; assert(l->nse->type == NFLNK); assert(l->symlink_done == 0); if (reply == NULL) { report_error(NONFATAL, "cr_symlink cancelled"); nameset_dele(l->nse); free(arg); return; } assert(reply->direction == REPLY); if (res->status != NFS_OK) { report_error(NONFATAL, "cr_symlink error %d: %s", res->status, nfs_errstr(res->status)); nameset_dele(l->nse); free(arg); return; } assert(res->optfh.present); assert(*((u_int64_t *)res->optfh.fh.data) != 0); nameset_setfh(l->nse, res->optfh.fh.data, res->optfh.fh.len); l->symlink_done = 1; Q_INSERT_HEAD(&cr_worklist, l, link); }
static void cr_write_callback(void *arg, struct nfsmsg *reply, u_int32_t xid) { struct cr_rec *f = (struct cr_rec *)arg; struct write_res *res = reply ? &reply->u.write_res : NULL; assert(f->nse->type == NFREG); assert(f->create_done == 1); if (reply == NULL) { report_error(NONFATAL, "cr_write cancelled"); free(arg); return; } assert(reply->direction == REPLY); if (res->status != NFS_OK) { #ifdef EXTRA_OUTPUT report_error(NONFATAL, "cr_write error %d: %s", res->status, nfs_errstr(res->status)); #endif free(arg); return; } f->size_done += res->count; if (res->wcc_data.after.present && res->wcc_data.after.fattr.fa_size != f->size_done) { report_error(NONFATAL, "cr_write response with bad size (got %d, expected %d)", (int)res->wcc_data.after.fattr.fa_size, f->size_done); } Q_INSERT_HEAD(&cr_worklist, f, link); }
static void connect_me(ENTRY *entry) { VCC *vcc; int fd; assert(entry->addr->sas_family == AF_ATMSVC); if ((fd = connect_vcc((struct sockaddr *) entry->addr,&entry->qos, entry->sndbuf,CLIP_DEFAULT_IDLETIMER)) < 0) return; vcc = alloc_t(VCC); vcc->active = 1; vcc->connecting = 1; vcc->fd = fd; vcc->entry = entry; Q_INSERT_HEAD(entry->vccs,vcc); }
static int want_arp_srv(const ITF *itf) { VCC *vcc; int fd; if (!itf->arp_srv) return -1; for (vcc = itf->arp_srv->vccs; vcc; vcc = vcc->next) if (!vcc->connecting) return 1; if (itf->arp_srv->vccs) return 0; if ((fd = connect_vcc((struct sockaddr *) itf->arp_srv->addr, &itf->arp_srv->qos,itf->arp_srv->sndbuf,CLIP_DEFAULT_IDLETIMER)) < 0) return 0; vcc = alloc_t(VCC); vcc->active = 1; vcc->connecting = 1; vcc->fd = fd; vcc->entry = itf->arp_srv; Q_INSERT_HEAD(itf->arp_srv->vccs,vcc); return 0; }
static void cr_mkdir_callback(void *arg, struct nfsmsg *reply, u_int32_t xid) { struct cr_rec *d = (struct cr_rec *)arg; struct mkdir_res *res = reply ? &reply->u.mkdir_res : NULL; assert(d->nse->type == NFDIR); if (reply == NULL) { report_error(NONFATAL, "cr_mkdir cancelled"); nameset_dele(d->nse); free(arg); return; } assert(reply->direction == REPLY); if (res->status != NFS_OK) { /* * special case this common error. */ if (res->status == NFSERR_EXIST) { report_error(NONFATAL, "mkdir returned NFSERR_EXIST.\n" "this will happen if you are re-running" "fstress without first deleting the old" "fstress created files"); } report_error(FATAL, "cr_mkdir error %d: %s", res->status, nfs_errstr(res->status)); nameset_dele(d->nse); free(arg); return; } assert(res->optfh.present); assert(*((u_int64_t *)res->optfh.fh.data) != 0); nameset_setfh(d->nse, res->optfh.fh.data, res->optfh.fh.len); assert(d->mkdir_done == 0); d->mkdir_done = 1; Q_INSERT_HEAD(&cr_worklist, d, link); }
static void accept_new(void) { char buffer[MAX_ATM_ADDR_LEN+1]; struct sockaddr_atmsvc addr; struct atm_qos qos; ENTRY *entry; VCC *vcc; int fd,error; socklen_t len,size; len = sizeof(addr); if ((fd = accept(incoming,(struct sockaddr *) &addr,&len)) < 0) { error = errno; diag(COMPONENT,DIAG_ERROR,"accept: %s",strerror(errno)); if (error == EUNATCH) { diag(COMPONENT,DIAG_WARN,"disabling SVCs"); (void) close(incoming); incoming = -1; } return; } /* the following code probably belongs to arp.c ... */ if (atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &addr,pretty) < 0) strcpy(buffer,"<atm2text error>"); diag(COMPONENT,DIAG_DEBUG,"Incoming call from %s",buffer); size = sizeof(qos); if (getsockopt(fd,SOL_ATM,SO_ATMQOS,&qos,&size) < 0) diag(COMPONENT,DIAG_FATAL,"getsockopt SO_ATMQOS: %s",strerror(errno)); if (size != sizeof(qos)) diag(COMPONENT,DIAG_FATAL,"SO_ATMQOS: size %d != %d",size,sizeof(qos)); if (ioctl(fd,ATMARP_MKIP,qos.txtp.traffic_class == ATM_NONE ? 0 : CLIP_DEFAULT_IDLETIMER) < 0) { diag(COMPONENT,DIAG_ERROR,"ioctl ATMARP_MKIP: %s",strerror(errno)); (void) do_close(fd); return; } vcc = alloc_t(VCC); vcc->active = 0; vcc->connecting = 0; vcc->fd = fd; if (qos.txtp.traffic_class == ATM_NONE) { vcc->entry = NULL; incoming_unidirectional(vcc); Q_INSERT_HEAD(unidirectional_vccs,vcc); return; } if (merge) { ITF *itf; for (itf = itfs; itf; itf = itf->next) { entry = lookup_addr(itf,&addr); if (entry) { vcc->entry = entry; Q_INSERT_HEAD(entry->vccs,vcc); if (entry->state == as_valid) { if (set_ip(vcc->fd,entry->ip) < 0) { diag(COMPONENT,DIAG_ERROR,"set_ip: %s", strerror(errno)); disconnect_vcc(vcc); } else set_sndbuf(vcc); } return; } } } entry = alloc_entry(1); entry->state = as_invalid; entry->addr = alloc_t(struct sockaddr_atmsvc); *entry->addr = addr; entry->flags = ATF_PUBL; Q_INSERT_HEAD(unknown_incoming,entry); vcc->entry = entry; Q_INSERT_HEAD(entry->vccs,vcc); incoming_call(vcc); }
static int learn(VCC *vcc,uint32_t ip,struct sockaddr_atmsvc *addr) { ENTRY *entry; ITF *itf; VCC *walk,*next; unsigned char *ipp; int result = 0; if (!ip) return 0; ipp = (unsigned char *) &ip; itf = lookup_itf_by_ip(ip); if (!itf) { diag(COMPONENT,DIAG_ERROR,"got unroutable IP address %d.%d.%d.%d", ipp[0],ipp[1],ipp[2],ipp[3]); return 0; } entry = lookup_ip(itf,ip); assert(!vcc || vcc->entry); /* * If the entry on which we received the update isn't dangling but it * doesn't correspond to the one with the address, ... */ if (entry && vcc && vcc->entry->itf && entry != vcc->entry) { diag(COMPONENT,DIAG_DEBUG,"collision on %d.%d.%d.%d",ipp[0],ipp[1], ipp[2],ipp[3]); return 0; } /* * If the entry on which we received the update is dangling and we found * an entry that already describes that IP address, ... */ if (entry && vcc && !vcc->entry->itf) { if (!entry->svc) { diag(COMPONENT,DIAG_ERROR,"attempt to overwrite PVC for IP " "%d.%d.%d.%d",ipp[0],ipp[1],ipp[2],ipp[3]); return 0; } STOP_TIMER(vcc->entry); Q_REMOVE(unknown_incoming,vcc->entry); free(vcc->entry); vcc->entry = entry; Q_INSERT_HEAD(entry->vccs,vcc); set_sndbuf(vcc); entry->flags &= ~ATF_NOVC; assert(!vcc->connecting); if (set_ip(vcc->fd,ip) < 0) { diag(COMPONENT,DIAG_ERROR,"set_ip: %s",strerror(errno)); disconnect_vcc(vcc); vcc = NULL; result = -1; } } /* * If we still don't have an entry, we try to use the entry that already * belongs to the VCC (InARP), or we create a new one (ARP). */ if (!entry) { if (vcc) { entry = vcc->entry; if (!entry->itf) { Q_REMOVE(unknown_incoming,entry); entry->sndbuf = itf->sndbuf; set_sndbuf(vcc); } else if (entry->ip && entry->ip != ip && (entry->flags & ATF_PERM) && !(entry->flags & ATF_ARPSRV)) { diag(COMPONENT,DIAG_ERROR,"ignoring attempt to change IP " "address of permanent entry (to %d.%d.%d.%d)",ipp[0], ipp[1],ipp[2],ipp[3]); return result; } } else { entry = alloc_entry(1); entry->flags = ATF_PUBL; } } if (!atmsvc_addr_in_use(*addr)) addr = NULL; if (entry->addr && addr && (entry->flags & ATF_PERM) && !atm_equal((struct sockaddr *) entry->addr,(struct sockaddr *) addr,0,0)) { diag(COMPONENT,DIAG_ERROR,"ignoring attempt to change ATM address of " "permanent entry"); return result; } if (entry->state == as_valid && entry->ip == ip && (!addr || (entry->addr && atm_equal((struct sockaddr *) entry->addr,(struct sockaddr *) addr,0, 0)))) return result; /* no news */ STOP_TIMER(entry); if (entry->ip != ip) send_notifications(entry,0); entry->ip = ip; if (!entry->itf) { entry->itf = itf; /* @@@ * Need to fix this is in case we allow entries without a valid IP * address but with a pre-set QOS, e.g. a VC on a given PVC with an * unknown remote end. */ entry->qos = entry->itf->qos; adjust_qos(entry->itf,&entry->qos,0); Q_INSERT_HEAD(itf->table,entry); } if (entry->itf != itf) diag(COMPONENT,DIAG_ERROR,"interesting, interface has changed ... " "(%d -> %d)",entry->itf->number,itf->number); if (addr) { if (!entry->addr) entry->addr = alloc(sizeof(*addr)); *entry->addr = *addr; if (merge) { ENTRY *incoming; while ((incoming = lookup_incoming(addr))) { STOP_TIMER(incoming); Q_REMOVE(unknown_incoming,incoming); incoming->vccs->entry = entry; Q_INSERT_HEAD(entry->vccs,incoming->vccs); set_sndbuf(incoming->vccs); free(incoming); } } } for (walk = entry->vccs; walk; walk = next) { next = walk->next; if (!walk->connecting) if (set_ip(walk->fd,ip) < 0) { diag(COMPONENT,DIAG_ERROR,"set_ip: %s",strerror(errno)); disconnect_vcc(walk); if (walk == vcc) result = -1; } } if (entry->state != as_valid) { if (!entry->vccs && itf->arp_srv && !(entry->flags & ATF_NOVC)) connect_me(entry); send_notifications(entry,1); } if ((entry->flags & ATF_ARPSRV) || !(entry->flags & ATF_PERM)) { if (entry->itf->arp_srv) START_TIMER(entry,CREVAL); else START_TIMER(entry,SREVAL); } entry->state = as_valid; return result; }
static int cr_newdir(nameset_entry_t parent, int maxdepth) { int weight = (*cr_d_weights)(); struct cr_rec *d; if ((d = malloc(sizeof(struct cr_rec))) == NULL) { report_perror(FATAL, "malloc error"); return -1; } bzero(d, sizeof(struct cr_rec)); if ((d->nse = nameset_alloc(parent, NFDIR, weight)) == NULL) { report_error(FATAL, "nameset_alloc error"); free(d); return -1; } if (nameset_getfname(d->nse, d->name, sizeof(d->name)) < 0) { report_error(FATAL, "nameset_getfname error"); free(d); return -1; } d->parent_nse = parent; d->maxdepth = maxdepth - 1; d->subdirs = (*cr_d_cnts)(); d->subfiles = (*cr_f_cnts)(); d->subsymlinks = (*cr_l_cnts)(); /* * if count is negative, scale it according to load level. */ if (d->subdirs < 0) { d->subdirs = -(d->subdirs) * cr_scale; } if (d->subfiles < 0) { d->subfiles = -(d->subfiles) * cr_scale; } if (d->subsymlinks < 0) { d->subsymlinks = -(d->subsymlinks) * cr_scale; } /* * prune things. first, enforce the max dirtree depth. * then, enforce limits on dirs, files, and symlinks. */ if (d->maxdepth <= 0) { d->subdirs = 0; } if (cr_d_max != -1) { if (d->subdirs > cr_d_max) { d->subdirs = cr_d_max; } cr_d_max -= d->subdirs; } if (cr_f_max != -1) { if (d->subfiles > cr_f_max) { d->subfiles = cr_f_max; } cr_f_max -= d->subfiles; } if (cr_l_max != -1) { if (d->subsymlinks > cr_l_max) { d->subsymlinks = cr_l_max; } cr_l_max -= d->subsymlinks; } d->nse->size = d->subdirs + d->subfiles; /* eventually */ Q_INSERT_HEAD(&cr_worklist, d, link); return 0; }