1*0490778eSAugustin Cavalier /** 2*0490778eSAugustin Cavalier * ioctl.c - Processing of ioctls 3*0490778eSAugustin Cavalier * 4*0490778eSAugustin Cavalier * This module is part of ntfs-3g library 5*0490778eSAugustin Cavalier * 6*0490778eSAugustin Cavalier * Copyright (c) 2014-2015 Jean-Pierre Andre 7*0490778eSAugustin Cavalier * Copyright (c) 2014 Red Hat, Inc. 8*0490778eSAugustin Cavalier * 9*0490778eSAugustin Cavalier * This program/include file is free software; you can redistribute it and/or 10*0490778eSAugustin Cavalier * modify it under the terms of the GNU General Public License as published 11*0490778eSAugustin Cavalier * by the Free Software Foundation; either version 2 of the License, or 12*0490778eSAugustin Cavalier * (at your option) any later version. 13*0490778eSAugustin Cavalier * 14*0490778eSAugustin Cavalier * This program/include file is distributed in the hope that it will be 15*0490778eSAugustin Cavalier * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 16*0490778eSAugustin Cavalier * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17*0490778eSAugustin Cavalier * GNU General Public License for more details. 18*0490778eSAugustin Cavalier * 19*0490778eSAugustin Cavalier * You should have received a copy of the GNU General Public License 20*0490778eSAugustin Cavalier * along with this program (in the main directory of the NTFS-3G 21*0490778eSAugustin Cavalier * distribution in the file COPYING); if not, write to the Free Software 22*0490778eSAugustin Cavalier * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23*0490778eSAugustin Cavalier */ 24*0490778eSAugustin Cavalier 25*0490778eSAugustin Cavalier #include "config.h" 26*0490778eSAugustin Cavalier 27*0490778eSAugustin Cavalier #ifdef HAVE_STDIO_H 28*0490778eSAugustin Cavalier #include <stdio.h> 29*0490778eSAugustin Cavalier #endif 30*0490778eSAugustin Cavalier #ifdef HAVE_INTTYPES_H 31*0490778eSAugustin Cavalier #include <inttypes.h> 32*0490778eSAugustin Cavalier #endif 33*0490778eSAugustin Cavalier #ifdef HAVE_STRING_H 34*0490778eSAugustin Cavalier #include <string.h> 35*0490778eSAugustin Cavalier #endif 36*0490778eSAugustin Cavalier #ifdef HAVE_ERRNO_H 37*0490778eSAugustin Cavalier #include <errno.h> 38*0490778eSAugustin Cavalier #endif 39*0490778eSAugustin Cavalier #ifdef HAVE_FCNTL_H 40*0490778eSAugustin Cavalier #include <fcntl.h> 41*0490778eSAugustin Cavalier #endif 42*0490778eSAugustin Cavalier #ifdef HAVE_UNISTD_H 43*0490778eSAugustin Cavalier #include <unistd.h> 44*0490778eSAugustin Cavalier #endif 45*0490778eSAugustin Cavalier #ifdef HAVE_STDLIB_H 46*0490778eSAugustin Cavalier #include <stdlib.h> 47*0490778eSAugustin Cavalier #endif 48*0490778eSAugustin Cavalier #ifdef HAVE_LIMITS_H 49*0490778eSAugustin Cavalier #include <limits.h> 50*0490778eSAugustin Cavalier #endif 51*0490778eSAugustin Cavalier #include <syslog.h> 52*0490778eSAugustin Cavalier #ifdef HAVE_SYS_TYPES_H 53*0490778eSAugustin Cavalier #include <sys/types.h> 54*0490778eSAugustin Cavalier #endif 55*0490778eSAugustin Cavalier #ifdef MAJOR_IN_MKDEV 56*0490778eSAugustin Cavalier #include <sys/mkdev.h> 57*0490778eSAugustin Cavalier #endif 58*0490778eSAugustin Cavalier #ifdef MAJOR_IN_SYSMACROS 59*0490778eSAugustin Cavalier #include <sys/sysmacros.h> 60*0490778eSAugustin Cavalier #endif 61*0490778eSAugustin Cavalier 62*0490778eSAugustin Cavalier #ifdef HAVE_SYS_STAT_H 63*0490778eSAugustin Cavalier #include <sys/stat.h> 64*0490778eSAugustin Cavalier #endif 65*0490778eSAugustin Cavalier 66*0490778eSAugustin Cavalier #ifdef HAVE_LINUX_FS_H 67*0490778eSAugustin Cavalier #include <linux/fs.h> 68*0490778eSAugustin Cavalier #endif 69*0490778eSAugustin Cavalier 70*0490778eSAugustin Cavalier #include "compat.h" 71*0490778eSAugustin Cavalier #include "debug.h" 72*0490778eSAugustin Cavalier #include "bitmap.h" 73*0490778eSAugustin Cavalier #include "attrib.h" 74*0490778eSAugustin Cavalier #include "inode.h" 75*0490778eSAugustin Cavalier #include "layout.h" 76*0490778eSAugustin Cavalier #include "volume.h" 77*0490778eSAugustin Cavalier #include "index.h" 78*0490778eSAugustin Cavalier #include "logging.h" 79*0490778eSAugustin Cavalier #include "ntfstime.h" 80*0490778eSAugustin Cavalier #include "unistr.h" 81*0490778eSAugustin Cavalier #include "dir.h" 82*0490778eSAugustin Cavalier #include "security.h" 83*0490778eSAugustin Cavalier #include "ioctl.h" 84*0490778eSAugustin Cavalier #include "misc.h" 85*0490778eSAugustin Cavalier 86*0490778eSAugustin Cavalier #if defined(FITRIM) && defined(BLKDISCARD) 87*0490778eSAugustin Cavalier 88*0490778eSAugustin Cavalier /* Issue a TRIM request to the underlying device for the given clusters. */ 89*0490778eSAugustin Cavalier static int fstrim_clusters(ntfs_volume *vol, LCN lcn, s64 length) 90*0490778eSAugustin Cavalier { 91*0490778eSAugustin Cavalier struct ntfs_device *dev = vol->dev; 92*0490778eSAugustin Cavalier uint64_t range[2]; 93*0490778eSAugustin Cavalier 94*0490778eSAugustin Cavalier ntfs_log_debug("fstrim_clusters: %lld length %lld\n", 95*0490778eSAugustin Cavalier (long long) lcn, (long long) length); 96*0490778eSAugustin Cavalier 97*0490778eSAugustin Cavalier range[0] = lcn << vol->cluster_size_bits; 98*0490778eSAugustin Cavalier range[1] = length << vol->cluster_size_bits; 99*0490778eSAugustin Cavalier 100*0490778eSAugustin Cavalier if (dev->d_ops->ioctl(dev, BLKDISCARD, range) == -1) { 101*0490778eSAugustin Cavalier ntfs_log_debug("fstrim_one_cluster: ioctl failed: %m\n"); 102*0490778eSAugustin Cavalier return -errno; 103*0490778eSAugustin Cavalier } 104*0490778eSAugustin Cavalier return 0; 105*0490778eSAugustin Cavalier } 106*0490778eSAugustin Cavalier 107*0490778eSAugustin Cavalier static int read_line(const char *path, char *line, size_t max_bytes) 108*0490778eSAugustin Cavalier { 109*0490778eSAugustin Cavalier FILE *fp; 110*0490778eSAugustin Cavalier 111*0490778eSAugustin Cavalier fp = fopen(path, "r"); 112*0490778eSAugustin Cavalier if (fp == NULL) 113*0490778eSAugustin Cavalier return -errno; 114*0490778eSAugustin Cavalier if (fgets(line, max_bytes, fp) == NULL) { 115*0490778eSAugustin Cavalier int ret = -EIO; /* fgets doesn't set errno */ 116*0490778eSAugustin Cavalier fclose(fp); 117*0490778eSAugustin Cavalier return ret; 118*0490778eSAugustin Cavalier } 119*0490778eSAugustin Cavalier fclose (fp); 120*0490778eSAugustin Cavalier return 0; 121*0490778eSAugustin Cavalier } 122*0490778eSAugustin Cavalier 123*0490778eSAugustin Cavalier static int read_u64(const char *path, u64 *n) 124*0490778eSAugustin Cavalier { 125*0490778eSAugustin Cavalier char line[64]; 126*0490778eSAugustin Cavalier int ret; 127*0490778eSAugustin Cavalier 128*0490778eSAugustin Cavalier ret = read_line(path, line, sizeof line); 129*0490778eSAugustin Cavalier if (ret) 130*0490778eSAugustin Cavalier return ret; 131*0490778eSAugustin Cavalier if (sscanf(line, "%" SCNu64, n) != 1) 132*0490778eSAugustin Cavalier return -EINVAL; 133*0490778eSAugustin Cavalier return 0; 134*0490778eSAugustin Cavalier } 135*0490778eSAugustin Cavalier 136*0490778eSAugustin Cavalier /* Find discard limits for current backing device. 137*0490778eSAugustin Cavalier */ 138*0490778eSAugustin Cavalier static int fstrim_limits(ntfs_volume *vol, 139*0490778eSAugustin Cavalier u64 *discard_alignment, 140*0490778eSAugustin Cavalier u64 *discard_granularity, 141*0490778eSAugustin Cavalier u64 *discard_max_bytes) 142*0490778eSAugustin Cavalier { 143*0490778eSAugustin Cavalier struct stat statbuf; 144*0490778eSAugustin Cavalier char path1[80], path2[80]; 145*0490778eSAugustin Cavalier int ret; 146*0490778eSAugustin Cavalier 147*0490778eSAugustin Cavalier /* Stat the backing device. Caller has ensured it is a block device. */ 148*0490778eSAugustin Cavalier if (stat(vol->dev->d_name, &statbuf) == -1) { 149*0490778eSAugustin Cavalier ntfs_log_debug("fstrim_limits: could not stat %s\n", 150*0490778eSAugustin Cavalier vol->dev->d_name); 151*0490778eSAugustin Cavalier return -errno; 152*0490778eSAugustin Cavalier } 153*0490778eSAugustin Cavalier 154*0490778eSAugustin Cavalier /* For whole devices, 155*0490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/discard_alignment 156*0490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/queue/discard_granularity 157*0490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/queue/discard_max_bytes 158*0490778eSAugustin Cavalier * will exist. 159*0490778eSAugustin Cavalier * For partitions, we also need to check the parent device: 160*0490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/../queue/discard_granularity 161*0490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/../queue/discard_max_bytes 162*0490778eSAugustin Cavalier */ 163*0490778eSAugustin Cavalier snprintf(path1, sizeof path1, "/sys/dev/block/%d:%d", 164*0490778eSAugustin Cavalier major(statbuf.st_rdev), minor(statbuf.st_rdev)); 165*0490778eSAugustin Cavalier 166*0490778eSAugustin Cavalier snprintf(path2, sizeof path2, "%s/discard_alignment", path1); 167*0490778eSAugustin Cavalier ret = read_u64(path2, discard_alignment); 168*0490778eSAugustin Cavalier if (ret) { 169*0490778eSAugustin Cavalier if (ret != -ENOENT) 170*0490778eSAugustin Cavalier return ret; 171*0490778eSAugustin Cavalier else 172*0490778eSAugustin Cavalier /* We would expect this file to exist on all 173*0490778eSAugustin Cavalier * modern kernels. But for the sake of very 174*0490778eSAugustin Cavalier * old kernels: 175*0490778eSAugustin Cavalier */ 176*0490778eSAugustin Cavalier goto not_found; 177*0490778eSAugustin Cavalier } 178*0490778eSAugustin Cavalier 179*0490778eSAugustin Cavalier snprintf(path2, sizeof path2, "%s/queue/discard_granularity", path1); 180*0490778eSAugustin Cavalier ret = read_u64(path2, discard_granularity); 181*0490778eSAugustin Cavalier if (ret) { 182*0490778eSAugustin Cavalier if (ret != -ENOENT) 183*0490778eSAugustin Cavalier return ret; 184*0490778eSAugustin Cavalier else { 185*0490778eSAugustin Cavalier snprintf(path2, sizeof path2, 186*0490778eSAugustin Cavalier "%s/../queue/discard_granularity", path1); 187*0490778eSAugustin Cavalier ret = read_u64(path2, discard_granularity); 188*0490778eSAugustin Cavalier if (ret) { 189*0490778eSAugustin Cavalier if (ret != -ENOENT) 190*0490778eSAugustin Cavalier return ret; 191*0490778eSAugustin Cavalier else 192*0490778eSAugustin Cavalier goto not_found; 193*0490778eSAugustin Cavalier } 194*0490778eSAugustin Cavalier } 195*0490778eSAugustin Cavalier } 196*0490778eSAugustin Cavalier 197*0490778eSAugustin Cavalier snprintf(path2, sizeof path2, "%s/queue/discard_max_bytes", path1); 198*0490778eSAugustin Cavalier ret = read_u64(path2, discard_max_bytes); 199*0490778eSAugustin Cavalier if (ret) { 200*0490778eSAugustin Cavalier if (ret != -ENOENT) 201*0490778eSAugustin Cavalier return ret; 202*0490778eSAugustin Cavalier else { 203*0490778eSAugustin Cavalier snprintf(path2, sizeof path2, 204*0490778eSAugustin Cavalier "%s/../queue/discard_max_bytes", path1); 205*0490778eSAugustin Cavalier ret = read_u64(path2, discard_max_bytes); 206*0490778eSAugustin Cavalier if (ret) { 207*0490778eSAugustin Cavalier if (ret != -ENOENT) 208*0490778eSAugustin Cavalier return ret; 209*0490778eSAugustin Cavalier else 210*0490778eSAugustin Cavalier goto not_found; 211*0490778eSAugustin Cavalier } 212*0490778eSAugustin Cavalier } 213*0490778eSAugustin Cavalier } 214*0490778eSAugustin Cavalier 215*0490778eSAugustin Cavalier return 0; 216*0490778eSAugustin Cavalier 217*0490778eSAugustin Cavalier not_found: 218*0490778eSAugustin Cavalier /* If we reach here then we didn't find the device. This is 219*0490778eSAugustin Cavalier * not an error, but set discard_max_bytes = 0 to indicate 220*0490778eSAugustin Cavalier * that discard is not available. 221*0490778eSAugustin Cavalier */ 222*0490778eSAugustin Cavalier *discard_alignment = 0; 223*0490778eSAugustin Cavalier *discard_granularity = 0; 224*0490778eSAugustin Cavalier *discard_max_bytes = 0; 225*0490778eSAugustin Cavalier return 0; 226*0490778eSAugustin Cavalier } 227*0490778eSAugustin Cavalier 228*0490778eSAugustin Cavalier #define FSTRIM_BUFSIZ 4096 229*0490778eSAugustin Cavalier 230*0490778eSAugustin Cavalier /* Trim the filesystem. 231*0490778eSAugustin Cavalier * 232*0490778eSAugustin Cavalier * Free blocks between 'start' and 'start+len-1' (both byte offsets) 233*0490778eSAugustin Cavalier * are found and TRIM requests are sent to the block device. 'minlen' 234*0490778eSAugustin Cavalier * is the minimum continguous free range to discard. 235*0490778eSAugustin Cavalier */ 236*0490778eSAugustin Cavalier static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed) 237*0490778eSAugustin Cavalier { 238*0490778eSAugustin Cavalier struct fstrim_range *range = data; 239*0490778eSAugustin Cavalier u64 start = range->start; 240*0490778eSAugustin Cavalier u64 len = range->len; 241*0490778eSAugustin Cavalier u64 minlen = range->minlen; 242*0490778eSAugustin Cavalier u64 discard_alignment, discard_granularity, discard_max_bytes; 243*0490778eSAugustin Cavalier u8 *buf = NULL; 244*0490778eSAugustin Cavalier LCN start_buf; 245*0490778eSAugustin Cavalier int ret; 246*0490778eSAugustin Cavalier 247*0490778eSAugustin Cavalier ntfs_log_debug("fstrim: start=%llu len=%llu minlen=%llu\n", 248*0490778eSAugustin Cavalier (unsigned long long) start, 249*0490778eSAugustin Cavalier (unsigned long long) len, 250*0490778eSAugustin Cavalier (unsigned long long) minlen); 251*0490778eSAugustin Cavalier 252*0490778eSAugustin Cavalier *trimmed = 0; 253*0490778eSAugustin Cavalier 254*0490778eSAugustin Cavalier /* Fail if user tries to use the fstrim -o/-l/-m options. 255*0490778eSAugustin Cavalier * XXX We could fix these limitations in future. 256*0490778eSAugustin Cavalier */ 257*0490778eSAugustin Cavalier if (start != 0 || len != (uint64_t)-1) { 258*0490778eSAugustin Cavalier ntfs_log_debug("fstrim: setting start or length is not supported\n"); 259*0490778eSAugustin Cavalier return -EINVAL; 260*0490778eSAugustin Cavalier } 261*0490778eSAugustin Cavalier if (minlen > vol->cluster_size) { 262*0490778eSAugustin Cavalier ntfs_log_debug("fstrim: minlen > cluster size is not supported\n"); 263*0490778eSAugustin Cavalier return -EINVAL; 264*0490778eSAugustin Cavalier } 265*0490778eSAugustin Cavalier 266*0490778eSAugustin Cavalier /* Only block devices are supported. It would be possible to 267*0490778eSAugustin Cavalier * support backing files (ie. without using loop) but the 268*0490778eSAugustin Cavalier * ioctls used to punch holes in files are completely 269*0490778eSAugustin Cavalier * different. 270*0490778eSAugustin Cavalier */ 271*0490778eSAugustin Cavalier if (!NDevBlock(vol->dev)) { 272*0490778eSAugustin Cavalier ntfs_log_debug("fstrim: not supported for non-block-device\n"); 273*0490778eSAugustin Cavalier return -EOPNOTSUPP; 274*0490778eSAugustin Cavalier } 275*0490778eSAugustin Cavalier 276*0490778eSAugustin Cavalier ret = fstrim_limits(vol, &discard_alignment, 277*0490778eSAugustin Cavalier &discard_granularity, &discard_max_bytes); 278*0490778eSAugustin Cavalier if (ret) 279*0490778eSAugustin Cavalier return ret; 280*0490778eSAugustin Cavalier if (discard_alignment != 0) { 281*0490778eSAugustin Cavalier ntfs_log_debug("fstrim: backing device is not aligned for discards\n"); 282*0490778eSAugustin Cavalier return -EOPNOTSUPP; 283*0490778eSAugustin Cavalier } 284*0490778eSAugustin Cavalier if (discard_granularity > vol->cluster_size) { 285*0490778eSAugustin Cavalier ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n"); 286*0490778eSAugustin Cavalier return -EOPNOTSUPP; 287*0490778eSAugustin Cavalier } 288*0490778eSAugustin Cavalier if (discard_max_bytes == 0) { 289*0490778eSAugustin Cavalier ntfs_log_debug("fstrim: backing device does not support discard (discard_max_bytes == 0)\n"); 290*0490778eSAugustin Cavalier return -EOPNOTSUPP; 291*0490778eSAugustin Cavalier } 292*0490778eSAugustin Cavalier 293*0490778eSAugustin Cavalier /* Sync the device before doing anything. */ 294*0490778eSAugustin Cavalier ret = ntfs_device_sync(vol->dev); 295*0490778eSAugustin Cavalier if (ret) 296*0490778eSAugustin Cavalier return ret; 297*0490778eSAugustin Cavalier 298*0490778eSAugustin Cavalier /* Read through the bitmap. */ 299*0490778eSAugustin Cavalier buf = ntfs_malloc(FSTRIM_BUFSIZ); 300*0490778eSAugustin Cavalier if (buf == NULL) 301*0490778eSAugustin Cavalier return -errno; 302*0490778eSAugustin Cavalier for (start_buf = 0; start_buf < vol->nr_clusters; 303*0490778eSAugustin Cavalier start_buf += FSTRIM_BUFSIZ * 8) { 304*0490778eSAugustin Cavalier s64 count; 305*0490778eSAugustin Cavalier s64 br; 306*0490778eSAugustin Cavalier LCN end_buf, start_lcn; 307*0490778eSAugustin Cavalier 308*0490778eSAugustin Cavalier /* start_buf is LCN of first cluster in the current buffer. 309*0490778eSAugustin Cavalier * end_buf is LCN of last cluster + 1 in the current buffer. 310*0490778eSAugustin Cavalier */ 311*0490778eSAugustin Cavalier end_buf = start_buf + FSTRIM_BUFSIZ*8; 312*0490778eSAugustin Cavalier if (end_buf > vol->nr_clusters) 313*0490778eSAugustin Cavalier end_buf = vol->nr_clusters; 314*0490778eSAugustin Cavalier count = (end_buf - start_buf) / 8; 315*0490778eSAugustin Cavalier 316*0490778eSAugustin Cavalier br = ntfs_attr_pread(vol->lcnbmp_na, start_buf/8, count, buf); 317*0490778eSAugustin Cavalier if (br != count) { 318*0490778eSAugustin Cavalier if (br >= 0) 319*0490778eSAugustin Cavalier ret = -EIO; 320*0490778eSAugustin Cavalier else 321*0490778eSAugustin Cavalier ret = -errno; 322*0490778eSAugustin Cavalier goto free_out; 323*0490778eSAugustin Cavalier } 324*0490778eSAugustin Cavalier 325*0490778eSAugustin Cavalier /* Trim the clusters in large as possible blocks, but 326*0490778eSAugustin Cavalier * not larger than discard_max_bytes. 327*0490778eSAugustin Cavalier */ 328*0490778eSAugustin Cavalier for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) { 329*0490778eSAugustin Cavalier if (!ntfs_bit_get(buf, start_lcn-start_buf)) { 330*0490778eSAugustin Cavalier LCN end_lcn; 331*0490778eSAugustin Cavalier 332*0490778eSAugustin Cavalier /* Cluster 'start_lcn' is not in use, 333*0490778eSAugustin Cavalier * find end of this run. 334*0490778eSAugustin Cavalier */ 335*0490778eSAugustin Cavalier end_lcn = start_lcn+1; 336*0490778eSAugustin Cavalier while (end_lcn < end_buf && 337*0490778eSAugustin Cavalier (u64) (end_lcn-start_lcn) << vol->cluster_size_bits 338*0490778eSAugustin Cavalier < discard_max_bytes && 339*0490778eSAugustin Cavalier !ntfs_bit_get(buf, end_lcn-start_buf)) 340*0490778eSAugustin Cavalier end_lcn++; 341*0490778eSAugustin Cavalier 342*0490778eSAugustin Cavalier ret = fstrim_clusters(vol, 343*0490778eSAugustin Cavalier start_lcn, end_lcn-start_lcn); 344*0490778eSAugustin Cavalier if (ret) 345*0490778eSAugustin Cavalier goto free_out; 346*0490778eSAugustin Cavalier 347*0490778eSAugustin Cavalier *trimmed += (end_lcn - start_lcn) 348*0490778eSAugustin Cavalier << vol->cluster_size_bits; 349*0490778eSAugustin Cavalier start_lcn = end_lcn-1; 350*0490778eSAugustin Cavalier } 351*0490778eSAugustin Cavalier } 352*0490778eSAugustin Cavalier } 353*0490778eSAugustin Cavalier 354*0490778eSAugustin Cavalier ret = 0; 355*0490778eSAugustin Cavalier free_out: 356*0490778eSAugustin Cavalier free(buf); 357*0490778eSAugustin Cavalier return ret; 358*0490778eSAugustin Cavalier } 359*0490778eSAugustin Cavalier 360*0490778eSAugustin Cavalier #endif /* FITRIM && BLKDISCARD */ 361*0490778eSAugustin Cavalier 362*0490778eSAugustin Cavalier int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg __attribute__((unused)), 363*0490778eSAugustin Cavalier unsigned int flags __attribute__((unused)), void *data) 364*0490778eSAugustin Cavalier { 365*0490778eSAugustin Cavalier int ret = 0; 366*0490778eSAugustin Cavalier 367*0490778eSAugustin Cavalier switch (cmd) { 368*0490778eSAugustin Cavalier #if defined(FITRIM) && defined(BLKDISCARD) 369*0490778eSAugustin Cavalier case FITRIM: 370*0490778eSAugustin Cavalier if (!ni || !data) 371*0490778eSAugustin Cavalier ret = -EINVAL; 372*0490778eSAugustin Cavalier else { 373*0490778eSAugustin Cavalier u64 trimmed; 374*0490778eSAugustin Cavalier struct fstrim_range *range = (struct fstrim_range*)data; 375*0490778eSAugustin Cavalier 376*0490778eSAugustin Cavalier ret = fstrim(ni->vol, data, &trimmed); 377*0490778eSAugustin Cavalier range->len = trimmed; 378*0490778eSAugustin Cavalier } 379*0490778eSAugustin Cavalier break; 380*0490778eSAugustin Cavalier #else 381*0490778eSAugustin Cavalier #warning Trimming not supported : FITRIM or BLKDISCARD not defined 382*0490778eSAugustin Cavalier #endif 383*0490778eSAugustin Cavalier default : 384*0490778eSAugustin Cavalier ret = -EINVAL; 385*0490778eSAugustin Cavalier break; 386*0490778eSAugustin Cavalier } 387*0490778eSAugustin Cavalier return (ret); 388*0490778eSAugustin Cavalier } 389