]>
Commit | Line | Data |
---|---|---|
eefdbb8e GKH |
1 | From 64d240b721b21e266ffde645ec965c3b6d1c551f Mon Sep 17 00:00:00 2001 |
2 | From: Akinobu Mita <akinobu.mita@gmail.com> | |
3 | Date: Mon, 13 Apr 2015 23:21:58 +0900 | |
4 | Subject: target/file: Fix UNMAP with DIF protection support | |
5 | ||
6 | From: Akinobu Mita <akinobu.mita@gmail.com> | |
7 | ||
8 | commit 64d240b721b21e266ffde645ec965c3b6d1c551f upstream. | |
9 | ||
10 | When UNMAP command is issued with DIF protection support enabled, | |
11 | the protection info for the unmapped region is remain unchanged. | |
12 | So READ command for the region causes data integrity failure. | |
13 | ||
14 | This fixes it by invalidating protection info for the unmapped region | |
15 | by filling with 0xff pattern. This change also adds helper function | |
16 | fd_do_prot_fill() in order to reduce code duplication with existing | |
17 | fd_format_prot(). | |
18 | ||
19 | Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> | |
20 | Reviewed-by: Sagi Grimberg <sagig@mellanox.com> | |
21 | Reviewed-by: "Martin K. Petersen" <martin.petersen@oracle.com> | |
22 | Cc: Christoph Hellwig <hch@lst.de> | |
23 | Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com> | |
24 | Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org> | |
25 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
26 | ||
27 | --- | |
28 | drivers/target/target_core_file.c | 86 ++++++++++++++++++++++++++------------ | |
29 | 1 file changed, 61 insertions(+), 25 deletions(-) | |
30 | ||
31 | --- a/drivers/target/target_core_file.c | |
32 | +++ b/drivers/target/target_core_file.c | |
33 | @@ -545,6 +545,56 @@ fd_execute_write_same(struct se_cmd *cmd | |
34 | return 0; | |
35 | } | |
36 | ||
37 | +static int | |
38 | +fd_do_prot_fill(struct se_device *se_dev, sector_t lba, sector_t nolb, | |
39 | + void *buf, size_t bufsize) | |
40 | +{ | |
41 | + struct fd_dev *fd_dev = FD_DEV(se_dev); | |
42 | + struct file *prot_fd = fd_dev->fd_prot_file; | |
43 | + sector_t prot_length, prot; | |
44 | + loff_t pos = lba * se_dev->prot_length; | |
45 | + | |
46 | + if (!prot_fd) { | |
47 | + pr_err("Unable to locate fd_dev->fd_prot_file\n"); | |
48 | + return -ENODEV; | |
49 | + } | |
50 | + | |
51 | + prot_length = nolb * se_dev->prot_length; | |
52 | + | |
53 | + for (prot = 0; prot < prot_length;) { | |
54 | + sector_t len = min_t(sector_t, bufsize, prot_length - prot); | |
55 | + ssize_t ret = kernel_write(prot_fd, buf, len, pos + prot); | |
56 | + | |
57 | + if (ret != len) { | |
58 | + pr_err("vfs_write to prot file failed: %zd\n", ret); | |
59 | + return ret < 0 ? ret : -ENODEV; | |
60 | + } | |
61 | + prot += ret; | |
62 | + } | |
63 | + | |
64 | + return 0; | |
65 | +} | |
66 | + | |
67 | +static int | |
68 | +fd_do_prot_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) | |
69 | +{ | |
70 | + void *buf; | |
71 | + int rc; | |
72 | + | |
73 | + buf = (void *)__get_free_page(GFP_KERNEL); | |
74 | + if (!buf) { | |
75 | + pr_err("Unable to allocate FILEIO prot buf\n"); | |
76 | + return -ENOMEM; | |
77 | + } | |
78 | + memset(buf, 0xff, PAGE_SIZE); | |
79 | + | |
80 | + rc = fd_do_prot_fill(cmd->se_dev, lba, nolb, buf, PAGE_SIZE); | |
81 | + | |
82 | + free_page((unsigned long)buf); | |
83 | + | |
84 | + return rc; | |
85 | +} | |
86 | + | |
87 | static sense_reason_t | |
88 | fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) | |
89 | { | |
90 | @@ -552,6 +602,12 @@ fd_do_unmap(struct se_cmd *cmd, void *pr | |
91 | struct inode *inode = file->f_mapping->host; | |
92 | int ret; | |
93 | ||
94 | + if (cmd->se_dev->dev_attrib.pi_prot_type) { | |
95 | + ret = fd_do_prot_unmap(cmd, lba, nolb); | |
96 | + if (ret) | |
97 | + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | |
98 | + } | |
99 | + | |
100 | if (S_ISBLK(inode->i_mode)) { | |
101 | /* The backend is block device, use discard */ | |
102 | struct block_device *bdev = inode->i_bdev; | |
103 | @@ -874,48 +930,28 @@ static int fd_init_prot(struct se_device | |
104 | ||
105 | static int fd_format_prot(struct se_device *dev) | |
106 | { | |
107 | - struct fd_dev *fd_dev = FD_DEV(dev); | |
108 | - struct file *prot_fd = fd_dev->fd_prot_file; | |
109 | - sector_t prot_length, prot; | |
110 | unsigned char *buf; | |
111 | - loff_t pos = 0; | |
112 | int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size; | |
113 | - int rc, ret = 0, size, len; | |
114 | + int ret; | |
115 | ||
116 | if (!dev->dev_attrib.pi_prot_type) { | |
117 | pr_err("Unable to format_prot while pi_prot_type == 0\n"); | |
118 | return -ENODEV; | |
119 | } | |
120 | - if (!prot_fd) { | |
121 | - pr_err("Unable to locate fd_dev->fd_prot_file\n"); | |
122 | - return -ENODEV; | |
123 | - } | |
124 | ||
125 | buf = vzalloc(unit_size); | |
126 | if (!buf) { | |
127 | pr_err("Unable to allocate FILEIO prot buf\n"); | |
128 | return -ENOMEM; | |
129 | } | |
130 | - prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length; | |
131 | - size = prot_length; | |
132 | ||
133 | pr_debug("Using FILEIO prot_length: %llu\n", | |
134 | - (unsigned long long)prot_length); | |
135 | + (unsigned long long)(dev->transport->get_blocks(dev) + 1) * | |
136 | + dev->prot_length); | |
137 | ||
138 | memset(buf, 0xff, unit_size); | |
139 | - for (prot = 0; prot < prot_length; prot += unit_size) { | |
140 | - len = min(unit_size, size); | |
141 | - rc = kernel_write(prot_fd, buf, len, pos); | |
142 | - if (rc != len) { | |
143 | - pr_err("vfs_write to prot file failed: %d\n", rc); | |
144 | - ret = -ENODEV; | |
145 | - goto out; | |
146 | - } | |
147 | - pos += len; | |
148 | - size -= len; | |
149 | - } | |
150 | - | |
151 | -out: | |
152 | + ret = fd_do_prot_fill(dev, 0, dev->transport->get_blocks(dev) + 1, | |
153 | + buf, unit_size); | |
154 | vfree(buf); | |
155 | return ret; | |
156 | } |