aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Pierre André <jean-pierre.andre@wanadoo.fr>2019-01-23 17:43:47 +0100
committerJean-Pierre André <jean-pierre.andre@wanadoo.fr>2019-01-23 17:43:47 +0100
commitb9ad82ced79163d28571a0be65196c078bd67ae6 (patch)
tree8a5062e62d47e96488c821451ef2bee93f3ab82e
parent1ae6d818f0d57f527eda37d692bbb51ceb44fe06 (diff)
downloadandroid_external_ntfs-3g-b9ad82ced79163d28571a0be65196c078bd67ae6.tar.gz
android_external_ntfs-3g-b9ad82ced79163d28571a0be65196c078bd67ae6.tar.bz2
android_external_ntfs-3g-b9ad82ced79163d28571a0be65196c078bd67ae6.zip
Truncated SSD trimming zones to granularity supported by the device
When the trimming granularity is greater than the cluster size, the free zones have to be truncated to match the granularity.
-rw-r--r--libntfs-3g/ioctl.c65
1 files changed, 47 insertions, 18 deletions
diff --git a/libntfs-3g/ioctl.c b/libntfs-3g/ioctl.c
index 2eef5a51..6c49395d 100644
--- a/libntfs-3g/ioctl.c
+++ b/libntfs-3g/ioctl.c
@@ -3,7 +3,7 @@
*
* This module is part of ntfs-3g library
*
- * Copyright (c) 2014-2015 Jean-Pierre Andre
+ * Copyright (c) 2014-2019 Jean-Pierre Andre
* Copyright (c) 2014 Red Hat, Inc.
*
* This program/include file is free software; you can redistribute it and/or
@@ -225,6 +225,24 @@ not_found:
return 0;
}
+static inline LCN align_up(ntfs_volume *vol, LCN lcn, u64 granularity)
+{
+ u64 aligned;
+
+ aligned = (lcn << vol->cluster_size_bits) + granularity - 1;
+ aligned -= aligned % granularity;
+ return (aligned >> vol->cluster_size_bits);
+}
+
+static inline u64 align_down(ntfs_volume *vol, u64 count, u64 granularity)
+{
+ u64 aligned;
+
+ aligned = count << vol->cluster_size_bits;
+ aligned -= aligned % granularity;
+ return (aligned >> vol->cluster_size_bits);
+}
+
#define FSTRIM_BUFSIZ 4096
/* Trim the filesystem.
@@ -255,11 +273,11 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
* XXX We could fix these limitations in future.
*/
if (start != 0 || len != (uint64_t)-1) {
- ntfs_log_debug("fstrim: setting start or length is not supported\n");
+ ntfs_log_error("fstrim: setting start or length is not supported\n");
return -EINVAL;
}
if (minlen > vol->cluster_size) {
- ntfs_log_debug("fstrim: minlen > cluster size is not supported\n");
+ ntfs_log_error("fstrim: minlen > cluster size is not supported\n");
return -EINVAL;
}
@@ -269,7 +287,7 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
* different.
*/
if (!NDevBlock(vol->dev)) {
- ntfs_log_debug("fstrim: not supported for non-block-device\n");
+ ntfs_log_error("fstrim: not supported for non-block-device\n");
return -EOPNOTSUPP;
}
@@ -278,15 +296,12 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
if (ret)
return ret;
if (discard_alignment != 0) {
- ntfs_log_debug("fstrim: backing device is not aligned for discards\n");
- return -EOPNOTSUPP;
- }
- if (discard_granularity > vol->cluster_size) {
- ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n");
+ ntfs_log_error("fstrim: backing device is not aligned for discards\n");
return -EOPNOTSUPP;
}
+
if (discard_max_bytes == 0) {
- ntfs_log_debug("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
+ ntfs_log_error("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
return -EOPNOTSUPP;
}
@@ -323,11 +338,14 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
}
/* Trim the clusters in large as possible blocks, but
- * not larger than discard_max_bytes.
+ * not larger than discard_max_bytes, and compatible
+ * with the supported trim granularity.
*/
for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) {
if (!ntfs_bit_get(buf, start_lcn-start_buf)) {
LCN end_lcn;
+ LCN aligned_lcn;
+ u64 aligned_count;
/* Cluster 'start_lcn' is not in use,
* find end of this run.
@@ -338,14 +356,25 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
< discard_max_bytes &&
!ntfs_bit_get(buf, end_lcn-start_buf))
end_lcn++;
-
- ret = fstrim_clusters(vol,
- start_lcn, end_lcn-start_lcn);
- if (ret)
- goto free_out;
-
- *trimmed += (end_lcn - start_lcn)
+ aligned_lcn = align_up(vol, start_lcn,
+ discard_granularity);
+ if (aligned_lcn >= end_lcn)
+ aligned_count = 0;
+ else {
+ aligned_count =
+ align_down(vol,
+ end_lcn - aligned_lcn,
+ discard_granularity);
+ }
+ if (aligned_count) {
+ ret = fstrim_clusters(vol,
+ aligned_lcn, aligned_count);
+ if (ret)
+ goto free_out;
+
+ *trimmed += aligned_count
<< vol->cluster_size_bits;
+ }
start_lcn = end_lcn-1;
}
}