1987da915Sopenharmony_ci/** 2987da915Sopenharmony_ci * ioctl.c - Processing of ioctls 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * This module is part of ntfs-3g library 5987da915Sopenharmony_ci * 6987da915Sopenharmony_ci * Copyright (c) 2014-2019 Jean-Pierre Andre 7987da915Sopenharmony_ci * Copyright (c) 2014 Red Hat, Inc. 8987da915Sopenharmony_ci * 9987da915Sopenharmony_ci * This program/include file is free software; you can redistribute it and/or 10987da915Sopenharmony_ci * modify it under the terms of the GNU General Public License as published 11987da915Sopenharmony_ci * by the Free Software Foundation; either version 2 of the License, or 12987da915Sopenharmony_ci * (at your option) any later version. 13987da915Sopenharmony_ci * 14987da915Sopenharmony_ci * This program/include file is distributed in the hope that it will be 15987da915Sopenharmony_ci * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 16987da915Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17987da915Sopenharmony_ci * GNU General Public License for more details. 18987da915Sopenharmony_ci * 19987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 20987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G 21987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 22987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23987da915Sopenharmony_ci */ 24987da915Sopenharmony_ci 25987da915Sopenharmony_ci#include "config.h" 26987da915Sopenharmony_ci 27987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 28987da915Sopenharmony_ci#include <stdio.h> 29987da915Sopenharmony_ci#endif 30987da915Sopenharmony_ci#ifdef HAVE_INTTYPES_H 31987da915Sopenharmony_ci#include <inttypes.h> 32987da915Sopenharmony_ci#endif 33987da915Sopenharmony_ci#ifdef HAVE_STRING_H 34987da915Sopenharmony_ci#include <string.h> 35987da915Sopenharmony_ci#endif 36987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H 37987da915Sopenharmony_ci#include <errno.h> 38987da915Sopenharmony_ci#endif 39987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H 40987da915Sopenharmony_ci#include <fcntl.h> 41987da915Sopenharmony_ci#endif 42987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H 43987da915Sopenharmony_ci#include <unistd.h> 44987da915Sopenharmony_ci#endif 45987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 46987da915Sopenharmony_ci#include <stdlib.h> 47987da915Sopenharmony_ci#endif 48987da915Sopenharmony_ci#ifdef HAVE_LIMITS_H 49987da915Sopenharmony_ci#include <limits.h> 50987da915Sopenharmony_ci#endif 51987da915Sopenharmony_ci#include <syslog.h> 52987da915Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H 53987da915Sopenharmony_ci#include <sys/types.h> 54987da915Sopenharmony_ci#endif 55987da915Sopenharmony_ci#ifdef MAJOR_IN_MKDEV 56987da915Sopenharmony_ci#include <sys/mkdev.h> 57987da915Sopenharmony_ci#endif 58987da915Sopenharmony_ci#ifdef MAJOR_IN_SYSMACROS 59987da915Sopenharmony_ci#include <sys/sysmacros.h> 60987da915Sopenharmony_ci#endif 61987da915Sopenharmony_ci 62987da915Sopenharmony_ci#ifdef HAVE_SYS_STAT_H 63987da915Sopenharmony_ci#include <sys/stat.h> 64987da915Sopenharmony_ci#endif 65987da915Sopenharmony_ci 66987da915Sopenharmony_ci#ifdef HAVE_LINUX_FS_H 67987da915Sopenharmony_ci#include <linux/fs.h> 68987da915Sopenharmony_ci#endif 69987da915Sopenharmony_ci 70987da915Sopenharmony_ci#include "compat.h" 71987da915Sopenharmony_ci#include "debug.h" 72987da915Sopenharmony_ci#include "bitmap.h" 73987da915Sopenharmony_ci#include "attrib.h" 74987da915Sopenharmony_ci#include "inode.h" 75987da915Sopenharmony_ci#include "layout.h" 76987da915Sopenharmony_ci#include "volume.h" 77987da915Sopenharmony_ci#include "index.h" 78987da915Sopenharmony_ci#include "logging.h" 79987da915Sopenharmony_ci#include "ntfstime.h" 80987da915Sopenharmony_ci#include "unistr.h" 81987da915Sopenharmony_ci#include "dir.h" 82987da915Sopenharmony_ci#include "security.h" 83987da915Sopenharmony_ci#include "ioctl.h" 84987da915Sopenharmony_ci#include "misc.h" 85987da915Sopenharmony_ci 86987da915Sopenharmony_ci#if defined(FITRIM) && defined(BLKDISCARD) 87987da915Sopenharmony_ci 88987da915Sopenharmony_ci/* Issue a TRIM request to the underlying device for the given clusters. */ 89987da915Sopenharmony_cistatic int fstrim_clusters(ntfs_volume *vol, LCN lcn, s64 length) 90987da915Sopenharmony_ci{ 91987da915Sopenharmony_ci struct ntfs_device *dev = vol->dev; 92987da915Sopenharmony_ci uint64_t range[2]; 93987da915Sopenharmony_ci 94987da915Sopenharmony_ci ntfs_log_debug("fstrim_clusters: %lld length %lld\n", 95987da915Sopenharmony_ci (long long) lcn, (long long) length); 96987da915Sopenharmony_ci 97987da915Sopenharmony_ci range[0] = lcn << vol->cluster_size_bits; 98987da915Sopenharmony_ci range[1] = length << vol->cluster_size_bits; 99987da915Sopenharmony_ci 100987da915Sopenharmony_ci if (dev->d_ops->ioctl(dev, BLKDISCARD, range) == -1) { 101987da915Sopenharmony_ci ntfs_log_debug("fstrim_one_cluster: ioctl failed: %m\n"); 102987da915Sopenharmony_ci return -errno; 103987da915Sopenharmony_ci } 104987da915Sopenharmony_ci return 0; 105987da915Sopenharmony_ci} 106987da915Sopenharmony_ci 107987da915Sopenharmony_cistatic int read_line(const char *path, char *line, size_t max_bytes) 108987da915Sopenharmony_ci{ 109987da915Sopenharmony_ci FILE *fp; 110987da915Sopenharmony_ci 111987da915Sopenharmony_ci fp = fopen(path, "r"); 112987da915Sopenharmony_ci if (fp == NULL) 113987da915Sopenharmony_ci return -errno; 114987da915Sopenharmony_ci if (fgets(line, max_bytes, fp) == NULL) { 115987da915Sopenharmony_ci int ret = -EIO; /* fgets doesn't set errno */ 116987da915Sopenharmony_ci fclose(fp); 117987da915Sopenharmony_ci return ret; 118987da915Sopenharmony_ci } 119987da915Sopenharmony_ci fclose (fp); 120987da915Sopenharmony_ci return 0; 121987da915Sopenharmony_ci} 122987da915Sopenharmony_ci 123987da915Sopenharmony_cistatic int read_u64(const char *path, u64 *n) 124987da915Sopenharmony_ci{ 125987da915Sopenharmony_ci char line[64]; 126987da915Sopenharmony_ci int ret; 127987da915Sopenharmony_ci 128987da915Sopenharmony_ci ret = read_line(path, line, sizeof line); 129987da915Sopenharmony_ci if (ret) 130987da915Sopenharmony_ci return ret; 131987da915Sopenharmony_ci if (sscanf(line, "%" SCNu64, n) != 1) 132987da915Sopenharmony_ci return -EINVAL; 133987da915Sopenharmony_ci return 0; 134987da915Sopenharmony_ci} 135987da915Sopenharmony_ci 136987da915Sopenharmony_ci/* Find discard limits for current backing device. 137987da915Sopenharmony_ci */ 138987da915Sopenharmony_cistatic int fstrim_limits(ntfs_volume *vol, 139987da915Sopenharmony_ci u64 *discard_alignment, 140987da915Sopenharmony_ci u64 *discard_granularity, 141987da915Sopenharmony_ci u64 *discard_max_bytes) 142987da915Sopenharmony_ci{ 143987da915Sopenharmony_ci struct stat statbuf; 144987da915Sopenharmony_ci char path1[40]; /* holds "/sys/dev/block/%d:%d" */ 145987da915Sopenharmony_ci char path2[40 + sizeof(path1)]; /* less than 40 bytes more than path1 */ 146987da915Sopenharmony_ci int ret; 147987da915Sopenharmony_ci 148987da915Sopenharmony_ci /* Stat the backing device. Caller has ensured it is a block device. */ 149987da915Sopenharmony_ci if (stat(vol->dev->d_name, &statbuf) == -1) { 150987da915Sopenharmony_ci ntfs_log_debug("fstrim_limits: could not stat %s\n", 151987da915Sopenharmony_ci vol->dev->d_name); 152987da915Sopenharmony_ci return -errno; 153987da915Sopenharmony_ci } 154987da915Sopenharmony_ci 155987da915Sopenharmony_ci /* For whole devices, 156987da915Sopenharmony_ci * /sys/dev/block/MAJOR:MINOR/discard_alignment 157987da915Sopenharmony_ci * /sys/dev/block/MAJOR:MINOR/queue/discard_granularity 158987da915Sopenharmony_ci * /sys/dev/block/MAJOR:MINOR/queue/discard_max_bytes 159987da915Sopenharmony_ci * will exist. 160987da915Sopenharmony_ci * For partitions, we also need to check the parent device: 161987da915Sopenharmony_ci * /sys/dev/block/MAJOR:MINOR/../queue/discard_granularity 162987da915Sopenharmony_ci * /sys/dev/block/MAJOR:MINOR/../queue/discard_max_bytes 163987da915Sopenharmony_ci */ 164987da915Sopenharmony_ci snprintf(path1, sizeof path1, "/sys/dev/block/%d:%d", 165987da915Sopenharmony_ci major(statbuf.st_rdev), minor(statbuf.st_rdev)); 166987da915Sopenharmony_ci 167987da915Sopenharmony_ci snprintf(path2, sizeof path2, "%s/discard_alignment", path1); 168987da915Sopenharmony_ci ret = read_u64(path2, discard_alignment); 169987da915Sopenharmony_ci if (ret) { 170987da915Sopenharmony_ci if (ret != -ENOENT) 171987da915Sopenharmony_ci return ret; 172987da915Sopenharmony_ci else 173987da915Sopenharmony_ci /* We would expect this file to exist on all 174987da915Sopenharmony_ci * modern kernels. But for the sake of very 175987da915Sopenharmony_ci * old kernels: 176987da915Sopenharmony_ci */ 177987da915Sopenharmony_ci goto not_found; 178987da915Sopenharmony_ci } 179987da915Sopenharmony_ci 180987da915Sopenharmony_ci snprintf(path2, sizeof path2, "%s/queue/discard_granularity", path1); 181987da915Sopenharmony_ci ret = read_u64(path2, discard_granularity); 182987da915Sopenharmony_ci if (ret) { 183987da915Sopenharmony_ci if (ret != -ENOENT) 184987da915Sopenharmony_ci return ret; 185987da915Sopenharmony_ci else { 186987da915Sopenharmony_ci snprintf(path2, sizeof path2, 187987da915Sopenharmony_ci "%s/../queue/discard_granularity", path1); 188987da915Sopenharmony_ci ret = read_u64(path2, discard_granularity); 189987da915Sopenharmony_ci if (ret) { 190987da915Sopenharmony_ci if (ret != -ENOENT) 191987da915Sopenharmony_ci return ret; 192987da915Sopenharmony_ci else 193987da915Sopenharmony_ci goto not_found; 194987da915Sopenharmony_ci } 195987da915Sopenharmony_ci } 196987da915Sopenharmony_ci } 197987da915Sopenharmony_ci 198987da915Sopenharmony_ci snprintf(path2, sizeof path2, "%s/queue/discard_max_bytes", path1); 199987da915Sopenharmony_ci ret = read_u64(path2, discard_max_bytes); 200987da915Sopenharmony_ci if (ret) { 201987da915Sopenharmony_ci if (ret != -ENOENT) 202987da915Sopenharmony_ci return ret; 203987da915Sopenharmony_ci else { 204987da915Sopenharmony_ci snprintf(path2, sizeof path2, 205987da915Sopenharmony_ci "%s/../queue/discard_max_bytes", path1); 206987da915Sopenharmony_ci ret = read_u64(path2, discard_max_bytes); 207987da915Sopenharmony_ci if (ret) { 208987da915Sopenharmony_ci if (ret != -ENOENT) 209987da915Sopenharmony_ci return ret; 210987da915Sopenharmony_ci else 211987da915Sopenharmony_ci goto not_found; 212987da915Sopenharmony_ci } 213987da915Sopenharmony_ci } 214987da915Sopenharmony_ci } 215987da915Sopenharmony_ci 216987da915Sopenharmony_ci return 0; 217987da915Sopenharmony_ci 218987da915Sopenharmony_cinot_found: 219987da915Sopenharmony_ci /* If we reach here then we didn't find the device. This is 220987da915Sopenharmony_ci * not an error, but set discard_max_bytes = 0 to indicate 221987da915Sopenharmony_ci * that discard is not available. 222987da915Sopenharmony_ci */ 223987da915Sopenharmony_ci *discard_alignment = 0; 224987da915Sopenharmony_ci *discard_granularity = 0; 225987da915Sopenharmony_ci *discard_max_bytes = 0; 226987da915Sopenharmony_ci return 0; 227987da915Sopenharmony_ci} 228987da915Sopenharmony_ci 229987da915Sopenharmony_cistatic inline LCN align_up(ntfs_volume *vol, LCN lcn, u64 granularity) 230987da915Sopenharmony_ci{ 231987da915Sopenharmony_ci u64 aligned; 232987da915Sopenharmony_ci 233987da915Sopenharmony_ci aligned = (lcn << vol->cluster_size_bits) + granularity - 1; 234987da915Sopenharmony_ci aligned -= aligned % granularity; 235987da915Sopenharmony_ci return (aligned >> vol->cluster_size_bits); 236987da915Sopenharmony_ci} 237987da915Sopenharmony_ci 238987da915Sopenharmony_cistatic inline u64 align_down(ntfs_volume *vol, u64 count, u64 granularity) 239987da915Sopenharmony_ci{ 240987da915Sopenharmony_ci u64 aligned; 241987da915Sopenharmony_ci 242987da915Sopenharmony_ci aligned = count << vol->cluster_size_bits; 243987da915Sopenharmony_ci aligned -= aligned % granularity; 244987da915Sopenharmony_ci return (aligned >> vol->cluster_size_bits); 245987da915Sopenharmony_ci} 246987da915Sopenharmony_ci 247987da915Sopenharmony_ci#define FSTRIM_BUFSIZ 4096 248987da915Sopenharmony_ci 249987da915Sopenharmony_ci/* Trim the filesystem. 250987da915Sopenharmony_ci * 251987da915Sopenharmony_ci * Free blocks between 'start' and 'start+len-1' (both byte offsets) 252987da915Sopenharmony_ci * are found and TRIM requests are sent to the block device. 'minlen' 253987da915Sopenharmony_ci * is the minimum continguous free range to discard. 254987da915Sopenharmony_ci */ 255987da915Sopenharmony_cistatic int fstrim(ntfs_volume *vol, void *data, u64 *trimmed) 256987da915Sopenharmony_ci{ 257987da915Sopenharmony_ci struct fstrim_range *range = data; 258987da915Sopenharmony_ci u64 start = range->start; 259987da915Sopenharmony_ci u64 len = range->len; 260987da915Sopenharmony_ci u64 minlen = range->minlen; 261987da915Sopenharmony_ci u64 discard_alignment, discard_granularity, discard_max_bytes; 262987da915Sopenharmony_ci u8 *buf = NULL; 263987da915Sopenharmony_ci LCN start_buf; 264987da915Sopenharmony_ci int ret; 265987da915Sopenharmony_ci 266987da915Sopenharmony_ci ntfs_log_debug("fstrim: start=%llu len=%llu minlen=%llu\n", 267987da915Sopenharmony_ci (unsigned long long) start, 268987da915Sopenharmony_ci (unsigned long long) len, 269987da915Sopenharmony_ci (unsigned long long) minlen); 270987da915Sopenharmony_ci 271987da915Sopenharmony_ci *trimmed = 0; 272987da915Sopenharmony_ci 273987da915Sopenharmony_ci /* Fail if user tries to use the fstrim -o/-l/-m options. 274987da915Sopenharmony_ci * XXX We could fix these limitations in future. 275987da915Sopenharmony_ci */ 276987da915Sopenharmony_ci if (start != 0 || len != (uint64_t)-1) { 277987da915Sopenharmony_ci ntfs_log_error("fstrim: setting start or length is not supported\n"); 278987da915Sopenharmony_ci return -EINVAL; 279987da915Sopenharmony_ci } 280987da915Sopenharmony_ci if (minlen > vol->cluster_size) { 281987da915Sopenharmony_ci ntfs_log_error("fstrim: minlen > cluster size is not supported\n"); 282987da915Sopenharmony_ci return -EINVAL; 283987da915Sopenharmony_ci } 284987da915Sopenharmony_ci 285987da915Sopenharmony_ci /* Only block devices are supported. It would be possible to 286987da915Sopenharmony_ci * support backing files (ie. without using loop) but the 287987da915Sopenharmony_ci * ioctls used to punch holes in files are completely 288987da915Sopenharmony_ci * different. 289987da915Sopenharmony_ci */ 290987da915Sopenharmony_ci if (!NDevBlock(vol->dev)) { 291987da915Sopenharmony_ci ntfs_log_error("fstrim: not supported for non-block-device\n"); 292987da915Sopenharmony_ci return -EOPNOTSUPP; 293987da915Sopenharmony_ci } 294987da915Sopenharmony_ci 295987da915Sopenharmony_ci ret = fstrim_limits(vol, &discard_alignment, 296987da915Sopenharmony_ci &discard_granularity, &discard_max_bytes); 297987da915Sopenharmony_ci if (ret) 298987da915Sopenharmony_ci return ret; 299987da915Sopenharmony_ci if (discard_alignment != 0) { 300987da915Sopenharmony_ci ntfs_log_error("fstrim: backing device is not aligned for discards\n"); 301987da915Sopenharmony_ci return -EOPNOTSUPP; 302987da915Sopenharmony_ci } 303987da915Sopenharmony_ci 304987da915Sopenharmony_ci if (discard_max_bytes == 0) { 305987da915Sopenharmony_ci ntfs_log_error("fstrim: backing device does not support discard (discard_max_bytes == 0)\n"); 306987da915Sopenharmony_ci return -EOPNOTSUPP; 307987da915Sopenharmony_ci } 308987da915Sopenharmony_ci 309987da915Sopenharmony_ci /* Sync the device before doing anything. */ 310987da915Sopenharmony_ci ret = ntfs_device_sync(vol->dev); 311987da915Sopenharmony_ci if (ret) 312987da915Sopenharmony_ci return ret; 313987da915Sopenharmony_ci 314987da915Sopenharmony_ci /* Read through the bitmap. */ 315987da915Sopenharmony_ci buf = ntfs_malloc(FSTRIM_BUFSIZ); 316987da915Sopenharmony_ci if (buf == NULL) 317987da915Sopenharmony_ci return -errno; 318987da915Sopenharmony_ci for (start_buf = 0; start_buf < vol->nr_clusters; 319987da915Sopenharmony_ci start_buf += FSTRIM_BUFSIZ * 8) { 320987da915Sopenharmony_ci s64 count; 321987da915Sopenharmony_ci s64 br; 322987da915Sopenharmony_ci LCN end_buf, start_lcn; 323987da915Sopenharmony_ci 324987da915Sopenharmony_ci /* start_buf is LCN of first cluster in the current buffer. 325987da915Sopenharmony_ci * end_buf is LCN of last cluster + 1 in the current buffer. 326987da915Sopenharmony_ci */ 327987da915Sopenharmony_ci end_buf = start_buf + FSTRIM_BUFSIZ*8; 328987da915Sopenharmony_ci if (end_buf > vol->nr_clusters) 329987da915Sopenharmony_ci end_buf = vol->nr_clusters; 330987da915Sopenharmony_ci count = (end_buf - start_buf) / 8; 331987da915Sopenharmony_ci 332987da915Sopenharmony_ci br = ntfs_attr_pread(vol->lcnbmp_na, start_buf/8, count, buf); 333987da915Sopenharmony_ci if (br != count) { 334987da915Sopenharmony_ci if (br >= 0) 335987da915Sopenharmony_ci ret = -EIO; 336987da915Sopenharmony_ci else 337987da915Sopenharmony_ci ret = -errno; 338987da915Sopenharmony_ci goto free_out; 339987da915Sopenharmony_ci } 340987da915Sopenharmony_ci 341987da915Sopenharmony_ci /* Trim the clusters in large as possible blocks, but 342987da915Sopenharmony_ci * not larger than discard_max_bytes, and compatible 343987da915Sopenharmony_ci * with the supported trim granularity. 344987da915Sopenharmony_ci */ 345987da915Sopenharmony_ci for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) { 346987da915Sopenharmony_ci if (!ntfs_bit_get(buf, start_lcn-start_buf)) { 347987da915Sopenharmony_ci LCN end_lcn; 348987da915Sopenharmony_ci LCN aligned_lcn; 349987da915Sopenharmony_ci u64 aligned_count; 350987da915Sopenharmony_ci 351987da915Sopenharmony_ci /* Cluster 'start_lcn' is not in use, 352987da915Sopenharmony_ci * find end of this run. 353987da915Sopenharmony_ci */ 354987da915Sopenharmony_ci end_lcn = start_lcn+1; 355987da915Sopenharmony_ci while (end_lcn < end_buf && 356987da915Sopenharmony_ci (u64) (end_lcn-start_lcn) << vol->cluster_size_bits 357987da915Sopenharmony_ci < discard_max_bytes && 358987da915Sopenharmony_ci !ntfs_bit_get(buf, end_lcn-start_buf)) 359987da915Sopenharmony_ci end_lcn++; 360987da915Sopenharmony_ci aligned_lcn = align_up(vol, start_lcn, 361987da915Sopenharmony_ci discard_granularity); 362987da915Sopenharmony_ci if (aligned_lcn >= end_lcn) 363987da915Sopenharmony_ci aligned_count = 0; 364987da915Sopenharmony_ci else { 365987da915Sopenharmony_ci aligned_count = 366987da915Sopenharmony_ci align_down(vol, 367987da915Sopenharmony_ci end_lcn - aligned_lcn, 368987da915Sopenharmony_ci discard_granularity); 369987da915Sopenharmony_ci } 370987da915Sopenharmony_ci if (aligned_count) { 371987da915Sopenharmony_ci ret = fstrim_clusters(vol, 372987da915Sopenharmony_ci aligned_lcn, aligned_count); 373987da915Sopenharmony_ci if (ret) 374987da915Sopenharmony_ci goto free_out; 375987da915Sopenharmony_ci 376987da915Sopenharmony_ci *trimmed += aligned_count 377987da915Sopenharmony_ci << vol->cluster_size_bits; 378987da915Sopenharmony_ci } 379987da915Sopenharmony_ci start_lcn = end_lcn-1; 380987da915Sopenharmony_ci } 381987da915Sopenharmony_ci } 382987da915Sopenharmony_ci } 383987da915Sopenharmony_ci 384987da915Sopenharmony_ci ret = 0; 385987da915Sopenharmony_cifree_out: 386987da915Sopenharmony_ci free(buf); 387987da915Sopenharmony_ci return ret; 388987da915Sopenharmony_ci} 389987da915Sopenharmony_ci 390987da915Sopenharmony_ci#endif /* FITRIM && BLKDISCARD */ 391987da915Sopenharmony_ci 392987da915Sopenharmony_ciint ntfs_ioctl(ntfs_inode *ni, unsigned long cmd, 393987da915Sopenharmony_ci void *arg __attribute__((unused)), 394987da915Sopenharmony_ci unsigned int flags __attribute__((unused)), void *data) 395987da915Sopenharmony_ci{ 396987da915Sopenharmony_ci int ret = 0; 397987da915Sopenharmony_ci 398987da915Sopenharmony_ci switch (cmd) { 399987da915Sopenharmony_ci#if defined(FITRIM) && defined(BLKDISCARD) 400987da915Sopenharmony_ci case FITRIM: 401987da915Sopenharmony_ci if (!ni || !data) 402987da915Sopenharmony_ci ret = -EINVAL; 403987da915Sopenharmony_ci else { 404987da915Sopenharmony_ci u64 trimmed; 405987da915Sopenharmony_ci struct fstrim_range *range = (struct fstrim_range*)data; 406987da915Sopenharmony_ci 407987da915Sopenharmony_ci ret = fstrim(ni->vol, data, &trimmed); 408987da915Sopenharmony_ci range->len = trimmed; 409987da915Sopenharmony_ci } 410987da915Sopenharmony_ci break; 411987da915Sopenharmony_ci#else 412987da915Sopenharmony_ci#warning Trimming not supported : FITRIM or BLKDISCARD not defined 413987da915Sopenharmony_ci#endif 414987da915Sopenharmony_ci default : 415987da915Sopenharmony_ci ret = -EINVAL; 416987da915Sopenharmony_ci break; 417987da915Sopenharmony_ci } 418987da915Sopenharmony_ci return (ret); 419987da915Sopenharmony_ci} 420