Author: rmacklem
Date: Sun Jul  8 18:15:55 2018
New Revision: 336093
URL: https://svnweb.freebsd.org/changeset/base/336093

Log:
  Fix the kernel part of pnfsdscopymr() to handle holes in the file being 
copied.
  
  If a mirrored DS is being recovered that has a lot of large sparse files,
  pnfsdscopymr(8) would use a lot of space on the recovered mirror since it
  would write the "holes" in the file being mirrored.
  This patch adds code to check for a "hole" and skip doing the write.
  The check is done on a "per PNFSDS_COPYSIZ size block", which is currently 
64K.
  I think that most file server file systems will be using a blocksize at
  least this large. If the file server is using a smaller blocksize and
  smaller holes need to be preserved, PNFSDS_COPYSIZ could be decreased.
  The block of 0s is malloc()d, since pnfsdcopymr(8) should be an infrequent
  occurrence.

Modified:
  head/sys/fs/nfsserver/nfs_nfsdkrpc.c
  head/sys/fs/nfsserver/nfs_nfsdstate.c

Modified: head/sys/fs/nfsserver/nfs_nfsdkrpc.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdkrpc.c        Sun Jul  8 16:51:54 2018        
(r336092)
+++ head/sys/fs/nfsserver/nfs_nfsdkrpc.c        Sun Jul  8 18:15:55 2018        
(r336093)
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
 NFSDLOCKMUTEX;
 NFSV4ROOTLOCKMUTEX;
 struct nfsv4lock nfsd_suspend_lock;
+char *nfsrv_zeropnfsdat = NULL;
 
 /*
  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
@@ -565,6 +566,8 @@ nfsrvd_init(int terminating)
                nfsrv_freealllayoutsanddevids();
                nfsrv_freeallbackchannel_xprts();
                svcpool_close(nfsrvd_pool);
+               free(nfsrv_zeropnfsdat, M_TEMP);
+               nfsrv_zeropnfsdat = NULL;
                NFSD_LOCK();
        } else {
                NFSD_UNLOCK();

Modified: head/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdstate.c       Sun Jul  8 16:51:54 2018        
(r336092)
+++ head/sys/fs/nfsserver/nfs_nfsdstate.c       Sun Jul  8 18:15:55 2018        
(r336093)
@@ -60,6 +60,7 @@ NFSSTATESPINLOCK;
 extern struct nfsdontlisthead nfsrv_dontlisthead;
 extern volatile int nfsrv_devidcnt;
 extern struct nfslayouthead nfsrv_recalllisthead;
+extern char *nfsrv_zeropnfsdat;
 
 SYSCTL_DECL(_vfs_nfsd);
 int    nfsrv_statehashsize = NFSSTATEHASHSIZE;
@@ -8124,9 +8125,15 @@ tryagain2:
                if (retacl != 0 && retacl != ENOATTR)
                        NFSD_DEBUG(1, "nfsrv_copymr: vop_getacl=%d\n", retacl);
                dat = malloc(PNFSDS_COPYSIZ, M_TEMP, M_WAITOK);
+               /* Malloc a block of 0s used to check for holes. */
+               if (nfsrv_zeropnfsdat == NULL)
+                       nfsrv_zeropnfsdat = malloc(PNFSDS_COPYSIZ, M_TEMP,
+                           M_WAITOK | M_ZERO);
                rdpos = wrpos = 0;
                mp = NULL;
                ret = vn_start_write(tvp, &mp, V_WAIT | PCATCH);
+               if (ret == 0)
+                       ret = VOP_GETATTR(fvp, &va, cred);
                aresid = 0;
                while (ret == 0 && aresid == 0) {
                        ret = vn_rdwr(UIO_READ, fvp, dat, PNFSDS_COPYSIZ,
@@ -8135,9 +8142,16 @@ tryagain2:
                        xfer = PNFSDS_COPYSIZ - aresid;
                        if (ret == 0 && xfer > 0) {
                                rdpos += xfer;
-                               ret = vn_rdwr(UIO_WRITE, tvp, dat, xfer,
-                                   wrpos, UIO_SYSSPACE, IO_NODELOCKED,
-                                   cred, NULL, NULL, p);
+                               /*
+                                * Skip the write for holes, except for the
+                                * last block.
+                                */
+                               if (xfer < PNFSDS_COPYSIZ || rdpos ==
+                                   va.va_size || NFSBCMP(dat,
+                                   nfsrv_zeropnfsdat, PNFSDS_COPYSIZ) != 0)
+                                       ret = vn_rdwr(UIO_WRITE, tvp, dat, xfer,
+                                           wrpos, UIO_SYSSPACE, IO_NODELOCKED,
+                                           cred, NULL, NULL, p);
                                if (ret == 0)
                                        wrpos += xfer;
                        }
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to