1 From c26a519da1ed182e7cfd67e7a353932dda53d811 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= <jpandre@users.sourceforge.net>
3 Date: Mon, 4 Aug 2014 17:39:50 +0200
4 Subject: [PATCH] Fixed fstrim(8) applied to partitions
6 The new way goes via /sys/dev/block/MAJOR:MINOR to map partitions to
7 devices and get discard parameters of the parent device. It also ensures
8 that the partition is aligned to the discard block size.
10 Contributed by Richard W.M. Jones
12 libntfs-3g/ioctl.c | 140 ++++++++++++++++++++++++++---------------------------
13 1 file changed, 68 insertions(+), 72 deletions(-)
15 diff --git a/libntfs-3g/ioctl.c b/libntfs-3g/ioctl.c
16 index bbbceb9..eb7c8e7 100644
17 --- a/libntfs-3g/ioctl.c
18 +++ b/libntfs-3g/ioctl.c
28 @@ -135,17 +133,14 @@ static int read_u64(const char *path, u64 *n)
31 /* Find discard limits for current backing device.
32 - * XXX Kernel makes this a pain in the neck.
34 -static int fstrim_limits(ntfs_volume *vol, u64 *discard_granularity,
35 +static int fstrim_limits(ntfs_volume *vol,
36 + u64 *discard_alignment,
37 + u64 *discard_granularity,
38 u64 *discard_max_bytes)
46 + char path1[80], path2[80];
49 /* Stat the backing device. Caller has ensured it is a block device. */
50 @@ -155,82 +150,78 @@ static int fstrim_limits(ntfs_volume *vol, u64 *discard_granularity,
54 - /* Now look for a /sys/block/<dev>/dev file which contains
56 + /* For whole devices,
57 + * /sys/dev/block/MAJOR:MINOR/discard_alignment
58 + * /sys/dev/block/MAJOR:MINOR/queue/discard_granularity
59 + * /sys/dev/block/MAJOR:MINOR/queue/discard_max_bytes
61 + * For partitions, we also need to check the parent device:
62 + * /sys/dev/block/MAJOR:MINOR/../queue/discard_granularity
63 + * /sys/dev/block/MAJOR:MINOR/../queue/discard_max_bytes
65 - snprintf(dev, sizeof dev, "%d:%d\n",
66 + snprintf(path1, sizeof path1, "/sys/dev/block/%d:%d",
67 major(statbuf.st_rdev), minor(statbuf.st_rdev));
69 - dir = opendir("/sys/block");
71 - ntfs_log_debug("fstrim_limits: could not open /sys/block\n");
73 + snprintf(path2, sizeof path2, "%s/discard_alignment", path1);
74 + ret = read_u64(path2, discard_alignment);
79 + /* We would expect this file to exist on all
80 + * modern kernels. But for the sake of very
90 - snprintf(path, sizeof path, "/sys/block/%s/dev", d->d_name);
91 - ret = read_line(path, line, sizeof line);
94 - if (strcmp(line, dev) == 0)
96 + snprintf(path2, sizeof path2, "%s/queue/discard_granularity", path1);
97 + ret = read_u64(path2, discard_granularity);
102 + snprintf(path2, sizeof path2,
103 + "%s/../queue/discard_granularity", path1);
104 + ret = read_u64(path2, discard_granularity);
106 + if (ret != -ENOENT)
114 - /* Check readdir didn't fail. */
117 - ntfs_log_debug("fstrim_limits: readdir failed\n");
119 + snprintf(path2, sizeof path2, "%s/queue/discard_max_bytes", path1);
120 + ret = read_u64(path2, discard_max_bytes);
122 + if (ret != -ENOENT)
125 + snprintf(path2, sizeof path2,
126 + "%s/../queue/discard_max_bytes", path1);
127 + ret = read_u64(path2, discard_max_bytes);
129 + if (ret != -ENOENT)
140 /* If we reach here then we didn't find the device. This is
141 * not an error, but set discard_max_bytes = 0 to indicate
142 * that discard is not available.
144 + *discard_alignment = 0;
145 *discard_granularity = 0;
146 *discard_max_bytes = 0;
147 - ntfs_log_debug("fstrim_limits: /sys/block entry corresponding to device %s not found\n",
153 - /* Found the device at /sys/block/ + d->d_name */
154 - snprintf (path, sizeof path,
155 - "/sys/block/%s/queue/discard_granularity",
157 - ret = read_u64(path, discard_granularity);
159 - ntfs_log_debug("fstrim_limits: could not read %s\n", path);
163 - snprintf (path, sizeof path,
164 - "/sys/block/%s/queue/discard_max_bytes",
166 - ret = read_u64(path, discard_max_bytes);
168 - ntfs_log_debug("fstrim_limits: could not read %s\n", path);
172 - ntfs_log_debug("fstrim_limits: device %s discard granularity = %llu max_bytes = %llu\n",
174 - (unsigned long long) *discard_granularity,
175 - (unsigned long long) *discard_max_bytes);
179 - if (closedir (dir) == -1) {
181 - ntfs_log_debug("fstrim_limits: closedir failed\n");
189 #define FSTRIM_BUFSIZ 4096
190 @@ -247,7 +238,7 @@ static int fstrim(ntfs_volume *vol, void *data)
191 u64 start = range->start;
192 u64 len = range->len;
193 u64 minlen = range->minlen;
194 - u64 discard_granularity, discard_max_bytes;
195 + u64 discard_alignment, discard_granularity, discard_max_bytes;
199 @@ -279,9 +270,14 @@ static int fstrim(ntfs_volume *vol, void *data)
203 - ret = fstrim_limits(vol, &discard_granularity, &discard_max_bytes);
204 + ret = fstrim_limits(vol, &discard_alignment,
205 + &discard_granularity, &discard_max_bytes);
208 + if (discard_alignment != 0) {
209 + ntfs_log_debug("fstrim: backing device is not aligned for discards\n");
210 + return -EOPNOTSUPP;
212 if (discard_granularity > vol->cluster_size) {
213 ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n");