1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
--- sys/contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c.orig
+++ sys/contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c
@@ -1364,6 +1364,19 @@
vec++;
total_len += crypt_len;
}
+ } else if (txtype == TX_CLONE_RANGE) {
+ const size_t o = offsetof(lr_clone_range_t, lr_nbps);
+ crypt_len = o - sizeof (lr_t);
+ dst_iovecs[vec].iov_base = (char *)dlrp + sizeof (lr_t);
+ dst_iovecs[vec].iov_len = crypt_len;
+
+ /* copy the bps now since they will not be encrypted */
+ memcpy(dlrp + o, slrp + o, lr_len - o);
+ memcpy(aadp, slrp + o, lr_len - o);
+ aadp += lr_len - o;
+ aad_len += lr_len - o;
+ vec++;
+ total_len += crypt_len;
} else {
crypt_len = lr_len - sizeof (lr_t);
dst_iovecs[vec].iov_base = (char *)dlrp +
--- sys/contrib/openzfs/module/os/linux/zfs/zio_crypt.c.orig
+++ sys/contrib/openzfs/module/os/linux/zfs/zio_crypt.c
@@ -1543,6 +1543,21 @@
nr_iovecs++;
total_len += crypt_len;
}
+ } else if (txtype == TX_CLONE_RANGE) {
+ const size_t o = offsetof(lr_clone_range_t, lr_nbps);
+ crypt_len = o - sizeof (lr_t);
+ src_iovecs[nr_iovecs].iov_base = slrp + sizeof (lr_t);
+ src_iovecs[nr_iovecs].iov_len = crypt_len;
+ dst_iovecs[nr_iovecs].iov_base = dlrp + sizeof (lr_t);
+ dst_iovecs[nr_iovecs].iov_len = crypt_len;
+
+ /* copy the bps now since they will not be encrypted */
+ memcpy(dlrp + o, slrp + o, lr_len - o);
+ memcpy(aadp, slrp + o, lr_len - o);
+ aadp += lr_len - o;
+ aad_len += lr_len - o;
+ nr_iovecs++;
+ total_len += crypt_len;
} else {
crypt_len = lr_len - sizeof (lr_t);
src_iovecs[nr_iovecs].iov_base = slrp + sizeof (lr_t);
--- sys/contrib/openzfs/module/zfs/dbuf.c.orig
+++ sys/contrib/openzfs/module/zfs/dbuf.c
@@ -2700,15 +2700,23 @@
* writes and clones into this block.
*/
mutex_enter(&db->db_mtx);
+ DBUF_VERIFY(db);
VERIFY(!dbuf_undirty(db, tx));
ASSERT3P(dbuf_find_dirty_eq(db, tx->tx_txg), ==, NULL);
if (db->db_buf != NULL) {
arc_buf_destroy(db->db_buf, db);
db->db_buf = NULL;
+ dbuf_clear_data(db);
}
+
+ db->db_state = DB_NOFILL;
+ DTRACE_SET_STATE(db, "allocating NOFILL buffer for clone");
+
+ DBUF_VERIFY(db);
mutex_exit(&db->db_mtx);
- dmu_buf_will_not_fill(db_fake, tx);
+ dbuf_noread(db);
+ (void) dbuf_dirty(db, tx);
}
void
--- sys/contrib/openzfs/module/zfs/dnode.c.orig
+++ sys/contrib/openzfs/module/zfs/dnode.c
@@ -1764,7 +1764,14 @@
}
/*
- * Checks if the dnode contains any uncommitted dirty records.
+ * Checks if the dnode itself is dirty, or is carrying any uncommitted records.
+ * It is important to check both conditions, as some operations (eg appending
+ * to a file) can dirty both as a single logical unit, but they are not synced
+ * out atomically, so checking one and not the other can result in an object
+ * appearing to be clean mid-way through a commit.
+ *
+ * Do not change this lightly! If you get it wrong, dmu_offset_next() can
+ * detect a hole where there is really data, leading to silent corruption.
*/
boolean_t
dnode_is_dirty(dnode_t *dn)
@@ -1772,7 +1779,8 @@
mutex_enter(&dn->dn_mtx);
for (int i = 0; i < TXG_SIZE; i++) {
- if (multilist_link_active(&dn->dn_dirty_link[i])) {
+ if (multilist_link_active(&dn->dn_dirty_link[i]) ||
+ !list_is_empty(&dn->dn_dirty_records[i])) {
mutex_exit(&dn->dn_mtx);
return (B_TRUE);
}
|