]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix errant EFAULT during writes (#8719)
authorBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 8 May 2019 17:04:04 +0000 (10:04 -0700)
committerGitHub <noreply@github.com>
Wed, 8 May 2019 17:04:04 +0000 (10:04 -0700)
Commit 98bb45e resolved a deadlock which could occur when
handling a page fault in zfs_write().  This change added
the uio_fault_disable field to the uio structure but failed
to initialize it to B_FALSE.  This uninitialized field would
cause uiomove_iov() to call __copy_from_user_inatomic()
instead of copy_from_user() resulting in unexpected EFAULTs.

Resolve the issue by fully initializing the uio, and clearing
the uio_fault_disable flags after it's used in zfs_write().

Additionally, reorder the uio_t field assignments to match
the order the fields are declared in the  structure.

Reviewed-by: Chunwei Chen <tuxoko@gmail.com>
Reviewed-by: Richard Laager <rlaager@wiktel.com>
Reviewed-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #8640
Closes #8719

module/zfs/zfs_vnops.c
module/zfs/zpl_file.c
module/zfs/zpl_inode.c
module/zfs/zvol.c

index 281f58249ad54b43a8cb103963ac5a47099ea1d1..27f179d826b9ae772edb4641d3e2f02a76c7ca1e 100644 (file)
@@ -822,6 +822,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                        uio->uio_fault_disable = B_TRUE;
                        error = dmu_write_uio_dbuf(sa_get_db(zp->z_sa_hdl),
                            uio, nbytes, tx);
+                       uio->uio_fault_disable = B_FALSE;
                        if (error == EFAULT) {
                                dmu_tx_commit(tx);
                                if (uio_prefaultpages(MIN(n, max_blksz), uio)) {
index 731836c2c71ee1a3ee2052f5a7b0cefad4a9a40d..acad4670d1c42dbc1582c0307846f6a08ae5dea8 100644 (file)
@@ -246,17 +246,17 @@ zpl_read_common_iovec(struct inode *ip, const struct iovec *iovp, size_t count,
     cred_t *cr, size_t skip)
 {
        ssize_t read;
-       uio_t uio;
+       uio_t uio = { { 0 }, 0 };
        int error;
        fstrans_cookie_t cookie;
 
        uio.uio_iov = iovp;
-       uio.uio_skip = skip;
-       uio.uio_resid = count;
        uio.uio_iovcnt = nr_segs;
        uio.uio_loffset = *ppos;
-       uio.uio_limit = MAXOFFSET_T;
        uio.uio_segflg = segment;
+       uio.uio_limit = MAXOFFSET_T;
+       uio.uio_resid = count;
+       uio.uio_skip = skip;
 
        cookie = spl_fstrans_mark();
        error = -zfs_read(ip, &uio, flags, cr);
@@ -356,7 +356,7 @@ zpl_write_common_iovec(struct inode *ip, const struct iovec *iovp, size_t count,
     cred_t *cr, size_t skip)
 {
        ssize_t wrote;
-       uio_t uio;
+       uio_t uio = { { 0 }, 0 };
        int error;
        fstrans_cookie_t cookie;
 
@@ -364,12 +364,12 @@ zpl_write_common_iovec(struct inode *ip, const struct iovec *iovp, size_t count,
                *ppos = i_size_read(ip);
 
        uio.uio_iov = iovp;
-       uio.uio_skip = skip;
-       uio.uio_resid = count;
        uio.uio_iovcnt = nr_segs;
        uio.uio_loffset = *ppos;
-       uio.uio_limit = MAXOFFSET_T;
        uio.uio_segflg = segment;
+       uio.uio_limit = MAXOFFSET_T;
+       uio.uio_resid = count;
+       uio.uio_skip = skip;
 
        cookie = spl_fstrans_mark();
        error = -zfs_write(ip, &uio, flags, cr);
index 720330a8b7d4b490120b0f1cd432797949973665..3f3b2e2dc53cb2b99072a7ed4848ef8c10fd0a6b 100644 (file)
@@ -493,7 +493,7 @@ zpl_get_link_common(struct dentry *dentry, struct inode *ip, char **link)
        fstrans_cookie_t cookie;
        cred_t *cr = CRED();
        struct iovec iov;
-       uio_t uio;
+       uio_t uio = { { 0 }, 0 };
        int error;
 
        crhold(cr);
@@ -503,9 +503,8 @@ zpl_get_link_common(struct dentry *dentry, struct inode *ip, char **link)
 
        uio.uio_iov = &iov;
        uio.uio_iovcnt = 1;
-       uio.uio_skip = 0;
-       uio.uio_resid = (MAXPATHLEN - 1);
        uio.uio_segflg = UIO_SYSSPACE;
+       uio.uio_resid = (MAXPATHLEN - 1);
 
        cookie = spl_fstrans_mark();
        error = -zfs_readlink(ip, &uio, cr);
index a77339d7f4c4865442376b237bc2221af77562f7..c29f65f676b96f970e1f8041008e4f960893170f 100644 (file)
@@ -727,12 +727,12 @@ static void
 uio_from_bio(uio_t *uio, struct bio *bio)
 {
        uio->uio_bvec = &bio->bi_io_vec[BIO_BI_IDX(bio)];
-       uio->uio_skip = BIO_BI_SKIP(bio);
-       uio->uio_resid = BIO_BI_SIZE(bio);
        uio->uio_iovcnt = bio->bi_vcnt - BIO_BI_IDX(bio);
        uio->uio_loffset = BIO_BI_SECTOR(bio) << 9;
-       uio->uio_limit = MAXOFFSET_T;
        uio->uio_segflg = UIO_BVEC;
+       uio->uio_limit = MAXOFFSET_T;
+       uio->uio_resid = BIO_BI_SIZE(bio);
+       uio->uio_skip = BIO_BI_SKIP(bio);
 }
 
 static void
@@ -742,7 +742,7 @@ zvol_write(void *arg)
 
        zv_request_t *zvr = arg;
        struct bio *bio = zvr->bio;
-       uio_t uio;
+       uio_t uio = { { 0 }, 0 };
        uio_from_bio(&uio, bio);
 
        zvol_state_t *zv = zvr->zv;
@@ -897,7 +897,7 @@ zvol_read(void *arg)
 
        zv_request_t *zvr = arg;
        struct bio *bio = zvr->bio;
-       uio_t uio;
+       uio_t uio = { { 0 }, 0 };
        uio_from_bio(&uio, bio);
 
        zvol_state_t *zv = zvr->zv;