diff -wNur linux-2.2.12/Documentation/Configure.help linux-cp/Documentation/Configure.help --- linux-2.2.12/Documentation/Configure.help Mon Sep 27 08:56:32 1999 +++ linux-cp/Documentation/Configure.help Tue Feb 22 18:21:17 2000 @@ -7372,6 +7372,16 @@ directories that are mount points on the local filesystem (this is how nfsd behaves on Sun systems), say yes here. If unsure, say N. +Enable copy support for NFS +CONFIG_NFSCP + If you would like support to copy NFS files using sendfile say Y. + When in doubt, say N. + +Enable debug for NFS copy support +CONFIG_NFSCP_DEBUG + If you would like some debug messages in the NFS copy support. + Useless if CONFIG_NFSCP is N. + OS/2 HPFS filesystem support (read only) CONFIG_HPFS_FS OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS diff -wNur linux-2.2.12/fs/Config.in linux-cp/fs/Config.in --- linux-2.2.12/fs/Config.in Mon Aug 9 14:04:40 1999 +++ linux-cp/fs/Config.in Tue Feb 22 18:12:23 2000 @@ -75,6 +75,10 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'NFS server support' CONFIG_NFSD fi + if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y"]; then + bool ' NFS copy support' CONFIG_NFSCP + bool ' NFS copy debug' CONFIG_NFSCP_DEBUG + fi if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NFSD" != "n" ]; then bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN fi diff -wNur linux-2.2.12/fs/nfs/Makefile linux-cp/fs/nfs/Makefile --- linux-2.2.12/fs/nfs/Makefile Wed Jun 24 16:30:10 1998 +++ linux-cp/fs/nfs/Makefile Tue Feb 22 17:57:27 2000 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile. O_TARGET := nfs.o -O_OBJS := inode.o file.o read.o write.o dir.o symlink.o proc.o \ +O_OBJS := inode.o file.o read.o write.o dir.o symlink.o proc.o copy.o \ nfs2xdr.o ifdef CONFIG_ROOT_NFS diff -wNur linux-2.2.12/fs/nfs/copy.c linux-cp/fs/nfs/copy.c --- linux-2.2.12/fs/nfs/copy.c Wed Dec 31 18:00:00 1969 +++ linux-cp/fs/nfs/copy.c Tue Mar 7 17:54:49 2000 @@ -0,0 +1,154 @@ +/* + * linux/fs/nfs/copy.c + * Copyright (C) 2000 {paurea,nemo}@gsyc.escet.urjc.es + * copy operation for NFS + */ + +/* Same includes of proc.c */ +#define NFS_NEED_XDR_TYPES 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + + +#include + + +#ifdef CONFIG_NFSCP + +static int initialized=0; +#ifdef CONFIG_NFSCP_DEBUG +int nfs_copy_debug=1; +#else +int nfs_copy_debug=0; +#endif + +int nfs_copy_enabled=1; +struct nfscp_stat { + int ncalls; + unsigned long nbytes; + int nerrs; +}; +static struct nfscp_stat stat; + + +#define cprintk(args...) do { extern int nfs_copy_debug; \ + if (nfs_copy_debug) printk(## args); } while(0) + + +static int +nfscp_rd(char *buf, char **start, off_t off, int len, int *eof, void *data) +{ + int l; + + if (len<=0) { + *eof=1; + return 0; + } + l = sprintf(buf,"cp %s: %d calls, %lu bytes, %d errors; debug %s\n", + (nfs_copy_enabled)?"enabled":"disabled", + stat.ncalls,stat.nbytes,stat.nerrs, + (nfs_copy_debug)?"on":"off" ); + l -= off; + if (l < len) + *eof=1; + else + l = len; + *start = buf + off; + return (l<=0) ? 0 : l; +} + +/* + * "debug" "nodebug" "clear" "on" "off" + */ +static int +nfscp_wr(struct file *file, const char *buf, unsigned long count, void *data) +{ + switch(*buf){ + case 'd': case 'D': + nfs_copy_debug=1; + return count; + case 'n': case 'N': + nfs_copy_debug=0; + return count; + case 'c': + memset(&stat,'\0',sizeof(stat)); + return count; + case 'o': case 'O': + switch (buf[1]){ + case 'n': + nfs_copy_enabled=1; + return count; + case 'f': + nfs_copy_enabled=0; + return count; + default: + return 0; + } + default: + return 0; + } +} + +static void nfscp_init(void) +{ + static struct proc_dir_entry *ent = NULL; + + memset(&stat,'\0',sizeof(stat)); + if (!ent && + (ent = create_proc_entry("fs/cp", S_IFREG|S_IRUGO|S_IWUSR, 0))){ + ent->read_proc = nfscp_rd; + ent->write_proc = nfscp_wr; + ent->data = &stat; + } +} + + +int +nfs_proc_copy(struct nfs_server *server, struct nfs_fh *fhdest, + struct nfs_fh *fhsrc, int swap, + unsigned long offdest, unsigned long offsrc, unsigned int *count, + struct nfs_fattr *fattrdest, struct nfs_fattr *fattrsrc, + char * host) +{ + int status; + struct nfs_copyargs arg = { + fhdest, fhsrc, offdest, offsrc, *count, host }; + struct nfs_copyres res = { fattrdest,fattrsrc, *count }; + + if (!initialized) { + nfscp_init(); + initialized=1; + } + + stat.ncalls++; + if (!count) + return 0; + cprintk("\ncp: %d @ %ld -> %ld @%s \n", *count,offsrc,offdest,host); + status = rpc_call(server->client, NFSPROC_COPY, &arg, &res, + swap? NFS_RPC_SWAPFLAGS : 0); + if (status>=0){ + *count=res.count; + stat.nbytes+=*count; + } else + stat.nerrs++; + cprintk("cp: result %d\n",status); + + return status; +} + + + +#endif /* CONFIG_NFSCP */ diff -wNur linux-2.2.12/fs/nfs/file.c linux-cp/fs/nfs/file.c --- linux-2.2.12/fs/nfs/file.c Mon Sep 27 08:56:31 1999 +++ linux-cp/fs/nfs/file.c Tue Mar 7 17:44:48 2000 @@ -14,6 +14,9 @@ * Total rewrite of read side for new NFS buffer cache.. Linus. * * nfs regular file handling functions + * + * Sun Feb 20 00:06:32 CST 2000 {paurea,nemo}@gsyc.escet.urjc.es + * Added nfs_file_copy. */ #include @@ -38,6 +41,12 @@ static int nfs_file_flush(struct file *); static int nfs_fsync(struct file *, struct dentry *dentry); + +#ifdef CONFIG_NFSCP +static ssize_t nfs_file_copy(struct file *, struct file *, + size_t, loff_t*,loff_t *); +#endif + static struct file_operations nfs_file_operations = { NULL, /* lseek - default */ nfs_file_read, /* read */ @@ -54,6 +63,9 @@ NULL, /* check_media_change */ NULL, /* revalidate */ nfs_lock, /* lock */ +#ifdef CONFIG_NFSCP + nfs_file_copy /* file copy */ +#endif }; struct inode_operations nfs_file_inode_operations = { @@ -104,6 +116,51 @@ return status; } + +#ifdef CONFIG_NFSCP + +#define cprintk(args...) do { extern int nfs_copy_debug; \ + if (nfs_copy_debug) printk(## args); } while(0) + +static ssize_t +nfs_file_copy(struct file * filedst, struct file * + filesrc, size_t count, loff_t * pposdst,loff_t * ppossrc) +{ + struct dentry * dentrydst= filedst->f_dentry; + struct dentry * dentrysrc= filesrc->f_dentry; + ssize_t result; + size_t left,total; + struct nfs_fattr fattrsrc,fattrdst; + + left=total=count; + do { + count=left; + if((result = + nfs_revalidate_inode(NFS_DSERVER(dentrydst), dentrydst))|| + (result = + nfs_revalidate_inode(NFS_DSERVER(dentrysrc), dentrysrc))) + return result; + + result = nfs_proc_copy(NFS_DSERVER(dentrysrc), + NFS_FH(dentrydst), + NFS_FH(dentrysrc), IS_SWAPFILE(inode), + (unsigned long) (*pposdst), + (unsigned long) (*ppossrc), + &count,&fattrdst,&fattrsrc, + NFS_HOST(dentrydst)); + if(result<0) + return result; + (*pposdst) += count; + (*ppossrc) += count; + cprintk("cp: %d bytes added to dst\n",result); + left -= count; + } while (left>0 && count>0); + + return total-left; +} + +#endif /* CONFIG_NFSCP */ + static ssize_t nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos) { diff -wNur linux-2.2.12/fs/nfs/inode.c linux-cp/fs/nfs/inode.c --- linux-2.2.12/fs/nfs/inode.c Mon Sep 27 08:56:32 1999 +++ linux-cp/fs/nfs/inode.c Tue Feb 22 19:04:00 2000 @@ -894,6 +894,10 @@ nfs_read_super, NULL }; + +#ifdef CONFIG_NFSCP + +#endif /* * Initialize NFS diff -wNur linux-2.2.12/fs/nfs/nfs2xdr.c linux-cp/fs/nfs/nfs2xdr.c --- linux-2.2.12/fs/nfs/nfs2xdr.c Sat Mar 6 16:21:13 1999 +++ linux-cp/fs/nfs/nfs2xdr.c Mon Feb 28 17:55:42 2000 @@ -5,6 +5,9 @@ * * Copyright (C) 1992, 1993, 1994 Rick Sladkey * Copyright (C) 1996 Olaf Kirch + * + * Sun Feb 20 00:14:32 CST 2000 {paurea,nemo}@gsyc.escet.urjc.es + * Added arguments for NFS copy op. */ #define NFS_NEED_XDR_TYPES @@ -42,6 +45,7 @@ #define NFS_sattr_sz 8 #define NFS_filename_sz 1+(NFS_MAXNAMLEN>>2) #define NFS_path_sz 1+(NFS_MAXPATHLEN>>2) +#define NFS_host_sz 1+(NFS_MAXHOSTNAME>>2) #define NFS_fattr_sz 17 #define NFS_info_sz 5 #define NFS_entry_sz NFS_filename_sz+3 @@ -65,6 +69,8 @@ #define NFS_stat_sz 1 #define NFS_readdirres_sz 1 #define NFS_statfsres_sz 1+NFS_info_sz +#define NFS_copyres_sz 1+NFS_fattr_sz+NFS_fattr_sz+1 +#define NFS_copyargs_sz 1+NFS_fattr_sz+NFS_fattr_sz+3+NFS_host_sz /* * Common NFS XDR functions as inlines @@ -217,6 +223,43 @@ return 0; } +#ifdef CONFIG_NFSCP +/* + * Arguments to a COPY call. + */ +static int +nfs_xdr_copyargs(struct rpc_rqst *req, u32 *p, struct nfs_copyargs *args) +{ + p = xdr_encode_fhandle(p, args->fhdest); + p = xdr_encode_fhandle(p, args->fhsrc); + *p++ = htonl(args->offsetdest); + *p++ = htonl(args->offsetsrc); + *p++ = htonl(args->count); + p = xdr_encode_string(p, args->host); + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + + return 0; +} + + +/* + * Decode COPY reply + */ +static int +nfs_xdr_copyres(struct rpc_rqst *req, u32 *p, struct nfs_copyres *res) +{ + int status,count; + if ((status = ntohl(*p++))) + return -nfs_stat_to_errno(status); + p = xdr_decode_fattr(p, res->fattrdest); + p = xdr_decode_fattr(p, res->fattrsrc); + res->count = count = ntohl(*p++); + + return count; +} +#endif /* CONFIG_NFSCP */ + + /* * Decode READ reply */ @@ -647,6 +690,29 @@ MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2 \ } +#ifdef CONFIG_NFSCP +static struct rpc_procinfo nfs_procedures[19] = { + PROC(null, enc_void, dec_void), + PROC(getattr, fhandle, attrstat), + PROC(setattr, sattrargs, attrstat), + PROC(root, enc_void, dec_void), + PROC(lookup, diropargs, diropres), + PROC(readlink, fhandle, readlinkres), + PROC(read, readargs, readres), + PROC(writecache, enc_void, dec_void), + PROC(write, writeargs, attrstat), + PROC(create, createargs, diropres), + PROC(remove, diropargs, stat), + PROC(rename, renameargs, stat), + PROC(link, linkargs, stat), + PROC(symlink, symlinkargs, stat), + PROC(mkdir, createargs, diropres), + PROC(rmdir, diropargs, stat), + PROC(readdir, readdirargs, readdirres), + PROC(statfs, fhandle, statfsres), + PROC(copy, copyargs, copyres), +}; +#else /* CONFIG_NFSCP */ static struct rpc_procinfo nfs_procedures[18] = { PROC(null, enc_void, dec_void), PROC(getattr, fhandle, attrstat), @@ -667,6 +733,7 @@ PROC(readdir, readdirargs, readdirres), PROC(statfs, fhandle, statfsres), }; +#endif /* !CONFIG_NFSCP */ static struct rpc_version nfs_version2 = { 2, @@ -687,3 +754,4 @@ nfs_version, &nfs_rpcstat, }; + diff -wNur linux-2.2.12/include/linux/fs.h linux-cp/include/linux/fs.h --- linux-2.2.12/include/linux/fs.h Fri Nov 19 18:18:20 1999 +++ linux-cp/include/linux/fs.h Mon Feb 28 17:11:45 2000 @@ -6,6 +6,11 @@ * structures etc. */ +/* Sun Feb 20 00:25:21 CST 2000 {paurea,nemo}@gsyc.escet.urjc.es + * Added copy. + */ + + #include #include #include @@ -594,6 +599,10 @@ int (*check_media_change) (kdev_t dev); int (*revalidate) (kdev_t dev); int (*lock) (struct file *, int, struct file_lock *); +#ifdef CONFIG_NFSCP + ssize_t (*copy) (struct file *, struct file *, size_t, + loff_t *,loff_t *); +#endif }; struct inode_operations { diff -wNur linux-2.2.12/include/linux/nfs.h linux-cp/include/linux/nfs.h --- linux-2.2.12/include/linux/nfs.h Sat Mar 6 16:21:13 1999 +++ linux-cp/include/linux/nfs.h Mon Feb 28 17:11:06 2000 @@ -1,11 +1,15 @@ /* * NFS protocol definitions + * + * Sun Feb 20 00:26:23 CST 2000 {paurea,nemo}@gsyc.escet.urjc.es + * Added support for copy. */ #ifndef _LINUX_NFS_H #define _LINUX_NFS_H #include +#define NFS_MAXHOSTNAME 255 /* for copy */ #define NFS_PORT 2049 #define NFS_MAXDATA 8192 #define NFS_MAXPATHLEN 1024 @@ -85,6 +89,7 @@ #define NFSPROC_RMDIR 15 #define NFSPROC_READDIR 16 #define NFSPROC_STATFS 17 +#define NFSPROC_COPY 18 /* Mount support for NFSroot */ #ifdef __KERNEL__ @@ -165,6 +170,17 @@ void * buffer; }; +#ifdef CONFIG_NFSCP +struct nfs_copyargs { + struct nfs_fh * fhdest; /* target fh */ + struct nfs_fh * fhsrc; /* source fh */ + __u32 offsetdest; /* file pos at target */ + __u32 offsetsrc; /* file pos at source */ + __u32 count; /* # of bytes */ + char * host; /* target host */ +}; +#endif + struct nfs_createargs { struct nfs_fh * fh; const char * name; @@ -207,6 +223,16 @@ struct nfs_fattr * fattr; unsigned int count; }; + + + +#ifdef CONFIG_NFSCP +struct nfs_copyres { + struct nfs_fattr * fattrdest; /* new target attrs */ + struct nfs_fattr * fattrsrc; /* new source attrs */ + unsigned int count; /* # of bytes copied */ +}; +#endif struct nfs_readlinkres { char ** string; diff -wNur linux-2.2.12/include/linux/nfs_fs.h linux-cp/include/linux/nfs_fs.h --- linux-2.2.12/include/linux/nfs_fs.h Fri Nov 19 18:18:37 1999 +++ linux-cp/include/linux/nfs_fs.h Mon Feb 28 17:12:09 2000 @@ -4,6 +4,9 @@ * Copyright (C) 1992 Rick Sladkey * * OS-specific nfs filesystem definitions and declarations + * + * Sun Feb 20 00:31:00 CST 2000 {paurea,nemo}@gsyc.escet.urjc.es + * Support for copy. */ #ifndef _LINUX_NFS_FS_H @@ -14,8 +17,10 @@ #include #include +#include #include #include +#include /* * Enable debugging support for nfs client. @@ -60,6 +65,7 @@ #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) #define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode))) #define NFS_CONGESTED(inode) (RPC_CONGESTED(NFS_CLIENT(inode))) +#define NFS_HOST(dentry) ((NFS_DSERVER(dentry))->hostname) #define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies) #define NFS_OLDMTIME(inode) ((inode)->u.nfs_i.read_cache_mtime) @@ -171,6 +177,15 @@ extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *res); +#ifdef CONFIG_NFSCP +extern int nfs_proc_copy(struct nfs_server *server, struct nfs_fh *fhdest, + struct nfs_fh *fhsrc, int swap, + unsigned long offsetdest, unsigned long offsetsrc, + unsigned int *count, + struct nfs_fattr *fattrdest, struct + nfs_fattr *fattrsrc, char * host); +extern int nfs_copy_debug; +#endif /* * linux/fs/nfs/inode.c diff -wNur linux-2.2.12/mm/filemap.c linux-cp/mm/filemap.c --- linux-2.2.12/mm/filemap.c Mon Sep 27 08:56:32 1999 +++ linux-cp/mm/filemap.c Tue Feb 29 19:25:31 2000 @@ -2,6 +2,9 @@ * linux/mm/filemap.c * * Copyright (C) 1994, 1995 Linus Torvalds + * + * Tue Feb 22 11:54:56 CST 2000 + * added support for copy {paurea,nemo}@gsyc.escet.urjc.es */ /* @@ -862,7 +865,18 @@ return written; } -asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) + +#ifdef CONFIG_NFSCP +static inline int is_remote(struct file *fp) { + return fp->f_op->copy!=NULL; +} +#define cprintk(args...) do { extern int nfs_copy_debug; \ + if (nfs_copy_debug) printk(## args); } while(0) +extern int nfs_copy_enabled; +#endif + +asmlinkage ssize_t +sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) { ssize_t retval; struct file * in_file, * out_file; @@ -908,6 +922,12 @@ if (retval) goto fput_out; + /* + * Tue Feb 22 11:54:56 CST 2000 + * added support for copy {paurea,nemo}@gsyc.escet.urjc.es + */ + +#ifndef CONFIG_NFSCP retval = 0; if (count) { read_descriptor_t desc; @@ -933,7 +953,53 @@ if (offset) put_user(pos, offset); } +#else /* !CONFIG_NFSCP */ + retval = 0; + if (count>0) { + loff_t pos = 0, *ppos; + loff_t *dppos= &out_file->f_pos; + retval = -EFAULT; + + if (offset) { + if (get_user(pos, offset)) + goto fput_out; + } else + pos = in_file->f_pos; + ppos = &pos; + if (nfs_copy_enabled && + is_remote(in_file) && is_remote(out_file)) { + size_t (*cpf)(struct file *,struct file*, + size_t,loff_t*,loff_t*); + + cprintk("cp: %d@%ld", in_fd, in_file->f_pos); + cprintk("-> %d@%ld", out_fd, out_file->f_pos); + if (!(cpf=in_file->f_op->copy)) + panic("cp: no copy for remote file"); + retval = (*cpf)(out_file,in_file,count,dppos,ppos); + cprintk("cp: copied remote file (%d)\n",retval); + cprintk("cp: %d@%ld", in_fd, *ppos); + cprintk("-> %d@%ld\n", out_fd, *dppos); + } + if (!nfs_copy_enabled || retval<0 || + !is_remote(in_file) || !is_remote(out_file)){ + read_descriptor_t desc; + printk("local sendfile call\n"); + desc.written = 0; + desc.count = count; + desc.buf = (char *) out_file; + desc.error = 0; + do_generic_file_read(in_file,ppos, &desc, + file_send_actor); + retval = desc.written; + if (!retval) + retval = desc.error; + } + if (offset) + put_user(pos, offset); + } else if (count<0) + retval=-EINVAL; +#endif /* !CONFIG_NFSCP */ fput_out: fput(out_file);