| Siguiente: GNU Free Documentation License Superior: Mejorando NFS Anterior: Cambios al cliente |
Función de atención a la petición de copy.
/*
* max # of read+writes to issue.
* 1 would be the traditional NFS value.
* However, latency can be much better if a whole file copy be
* copied within a single request.
*/
#define MAX_WORK 8
int nfsd_nfsproc_copy_2(copyargs *argp, struct svc_req *rqstp)
{
int sfd=-1,dfd=-1;
nfsstat status=NFS_OK;
int limit;
int islcl;
fhcache *sfhc,*dfhc;
static char lclhost[NFS_MAXHOSTLEN+1];
static int lclknown=0;
u_int nleft;
struct writeargs warg;
char *host=argp->hostname;
CLIENT *cp=NULL;
copyokres *res = &result.copyres.copyres_u.reply;
if (!lclknown){
if (gethostname(lclhost,NFS_MAXHOSTLEN)) {
Dprintf(L_ERROR,"gethostname failed");
return -1;
}
lclknown=1;
}
islcl=(!strcmp(host,"localhost") || !strcmp(host,lclhost));
if (islcl)
Dprintf(D_CALL,"copy to %s (local)",host);
else
Dprintf(D_CALL,"copy to %s (remote)",host);
sfd=getfd(&argp->filesrc,rqstp,argp->offsetsrc,&status,O_RDONLY,&sfhc);
if (islcl)
dfd=getfd(&argp->filedest,rqstp,argp->offsetdest,&status,O_WRONLY,
&dfhc);
else {
warg.file= argp->filedest;
warg.offset=argp->offsetdest;
warg.beginoffset=argp->offsetdest;
warg.data.data_val=iobuf;
if(!(cp=clnt_create(host,NFS_PROGRAM,NFS_VERSION,"udp"))){
Dprintf(L_ERROR,"unable to create client");
clnt_pcreateerror(host);
status =-1;
goto failure;
}
}
if (sfd<0 || (islcl && dfd<0)){
Dprintf(L_ERROR,"unable to open either src or dst");
goto failure;
}
/* Ok, got descriptors and/or the client connection: do the job */
nleft=argp->count;
res->count=0;
if (argp->offsetsrc == 0 && log_transfers)
nfsd_xferlog(rqstp, "<", sfhc->path);
for (limit=MAX_WORK ; limit>0 && nleft>0; limit--) {
u_int nbytes = nleft;
ssize_t rdres,wrres;
attrstat *rpcres;
errno=0;
if (nbytes > NFS_MAXDATA)
nbytes=NFS_MAXDATA;
rdres= read(sfd,iobuf,nbytes);
if (rdres <0)
Dprintf(L_ERROR,"read failed");
else if (!rdres || errno){
status = NFS_OK;
if (errno)
status=nfs_errno();
break;
} else
res->count += rdres;
if((status=fhc_getattr(sfhc, &res->attributessrc,NULL,rqstp))){
Dprintf(L_ERROR,"src fh status is not ok");
goto failure;
}
if (islcl) {
if ((wrres=write(dfd,iobuf,rdres))!=rdres) {
Dprintf(L_ERROR,"write failed (%d)",errno);
goto failure;
}
if((status=fhc_getattr(dfhc,
&res->attributesdest,NULL,rqstp))){
Dprintf(L_ERROR,"dst fh status is not ok");
goto failure;
}
} else {
warg.totalcount=warg.data.data_len=rdres;
if (!(rpcres=nfsproc_write_2(&warg,cp)) ||
rpcres->status != NFS_OK){
clnt_perror(cp, "write failed");
goto failure;
}
memcpy(&res->attributesdest,
&rpcres->attrstat_u.attributes,
sizeof(res->attributesdest));
warg.offset += rdres;
warg.beginoffset += rdres;
}
nleft -= rdres;
}
failure:
if (sfd>=0)
fd_inactive(sfd);
if (dfd>=0)
fd_inactive(dfd);
if (cp)
clnt_destroy(cp);
return status;
}