10490778eSAugustin Cavalier /**
20490778eSAugustin Cavalier * ioctl.c - Processing of ioctls
30490778eSAugustin Cavalier *
40490778eSAugustin Cavalier * This module is part of ntfs-3g library
50490778eSAugustin Cavalier *
6*9102cad6SAugustin Cavalier * Copyright (c) 2014-2019 Jean-Pierre Andre
70490778eSAugustin Cavalier * Copyright (c) 2014 Red Hat, Inc.
80490778eSAugustin Cavalier *
90490778eSAugustin Cavalier * This program/include file is free software; you can redistribute it and/or
100490778eSAugustin Cavalier * modify it under the terms of the GNU General Public License as published
110490778eSAugustin Cavalier * by the Free Software Foundation; either version 2 of the License, or
120490778eSAugustin Cavalier * (at your option) any later version.
130490778eSAugustin Cavalier *
140490778eSAugustin Cavalier * This program/include file is distributed in the hope that it will be
150490778eSAugustin Cavalier * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
160490778eSAugustin Cavalier * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
170490778eSAugustin Cavalier * GNU General Public License for more details.
180490778eSAugustin Cavalier *
190490778eSAugustin Cavalier * You should have received a copy of the GNU General Public License
200490778eSAugustin Cavalier * along with this program (in the main directory of the NTFS-3G
210490778eSAugustin Cavalier * distribution in the file COPYING); if not, write to the Free Software
220490778eSAugustin Cavalier * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
230490778eSAugustin Cavalier */
240490778eSAugustin Cavalier
250490778eSAugustin Cavalier #include "config.h"
260490778eSAugustin Cavalier
270490778eSAugustin Cavalier #ifdef HAVE_STDIO_H
280490778eSAugustin Cavalier #include <stdio.h>
290490778eSAugustin Cavalier #endif
300490778eSAugustin Cavalier #ifdef HAVE_INTTYPES_H
310490778eSAugustin Cavalier #include <inttypes.h>
320490778eSAugustin Cavalier #endif
330490778eSAugustin Cavalier #ifdef HAVE_STRING_H
340490778eSAugustin Cavalier #include <string.h>
350490778eSAugustin Cavalier #endif
360490778eSAugustin Cavalier #ifdef HAVE_ERRNO_H
370490778eSAugustin Cavalier #include <errno.h>
380490778eSAugustin Cavalier #endif
390490778eSAugustin Cavalier #ifdef HAVE_FCNTL_H
400490778eSAugustin Cavalier #include <fcntl.h>
410490778eSAugustin Cavalier #endif
420490778eSAugustin Cavalier #ifdef HAVE_UNISTD_H
430490778eSAugustin Cavalier #include <unistd.h>
440490778eSAugustin Cavalier #endif
450490778eSAugustin Cavalier #ifdef HAVE_STDLIB_H
460490778eSAugustin Cavalier #include <stdlib.h>
470490778eSAugustin Cavalier #endif
480490778eSAugustin Cavalier #ifdef HAVE_LIMITS_H
490490778eSAugustin Cavalier #include <limits.h>
500490778eSAugustin Cavalier #endif
510490778eSAugustin Cavalier #include <syslog.h>
520490778eSAugustin Cavalier #ifdef HAVE_SYS_TYPES_H
530490778eSAugustin Cavalier #include <sys/types.h>
540490778eSAugustin Cavalier #endif
550490778eSAugustin Cavalier #ifdef MAJOR_IN_MKDEV
560490778eSAugustin Cavalier #include <sys/mkdev.h>
570490778eSAugustin Cavalier #endif
580490778eSAugustin Cavalier #ifdef MAJOR_IN_SYSMACROS
590490778eSAugustin Cavalier #include <sys/sysmacros.h>
600490778eSAugustin Cavalier #endif
610490778eSAugustin Cavalier
620490778eSAugustin Cavalier #ifdef HAVE_SYS_STAT_H
630490778eSAugustin Cavalier #include <sys/stat.h>
640490778eSAugustin Cavalier #endif
650490778eSAugustin Cavalier
660490778eSAugustin Cavalier #ifdef HAVE_LINUX_FS_H
670490778eSAugustin Cavalier #include <linux/fs.h>
680490778eSAugustin Cavalier #endif
690490778eSAugustin Cavalier
700490778eSAugustin Cavalier #include "compat.h"
710490778eSAugustin Cavalier #include "debug.h"
720490778eSAugustin Cavalier #include "bitmap.h"
730490778eSAugustin Cavalier #include "attrib.h"
740490778eSAugustin Cavalier #include "inode.h"
750490778eSAugustin Cavalier #include "layout.h"
760490778eSAugustin Cavalier #include "volume.h"
770490778eSAugustin Cavalier #include "index.h"
780490778eSAugustin Cavalier #include "logging.h"
790490778eSAugustin Cavalier #include "ntfstime.h"
800490778eSAugustin Cavalier #include "unistr.h"
810490778eSAugustin Cavalier #include "dir.h"
820490778eSAugustin Cavalier #include "security.h"
830490778eSAugustin Cavalier #include "ioctl.h"
840490778eSAugustin Cavalier #include "misc.h"
850490778eSAugustin Cavalier
860490778eSAugustin Cavalier #if defined(FITRIM) && defined(BLKDISCARD)
870490778eSAugustin Cavalier
880490778eSAugustin Cavalier /* Issue a TRIM request to the underlying device for the given clusters. */
fstrim_clusters(ntfs_volume * vol,LCN lcn,s64 length)890490778eSAugustin Cavalier static int fstrim_clusters(ntfs_volume *vol, LCN lcn, s64 length)
900490778eSAugustin Cavalier {
910490778eSAugustin Cavalier struct ntfs_device *dev = vol->dev;
920490778eSAugustin Cavalier uint64_t range[2];
930490778eSAugustin Cavalier
940490778eSAugustin Cavalier ntfs_log_debug("fstrim_clusters: %lld length %lld\n",
950490778eSAugustin Cavalier (long long) lcn, (long long) length);
960490778eSAugustin Cavalier
970490778eSAugustin Cavalier range[0] = lcn << vol->cluster_size_bits;
980490778eSAugustin Cavalier range[1] = length << vol->cluster_size_bits;
990490778eSAugustin Cavalier
1000490778eSAugustin Cavalier if (dev->d_ops->ioctl(dev, BLKDISCARD, range) == -1) {
1010490778eSAugustin Cavalier ntfs_log_debug("fstrim_one_cluster: ioctl failed: %m\n");
1020490778eSAugustin Cavalier return -errno;
1030490778eSAugustin Cavalier }
1040490778eSAugustin Cavalier return 0;
1050490778eSAugustin Cavalier }
1060490778eSAugustin Cavalier
read_line(const char * path,char * line,size_t max_bytes)1070490778eSAugustin Cavalier static int read_line(const char *path, char *line, size_t max_bytes)
1080490778eSAugustin Cavalier {
1090490778eSAugustin Cavalier FILE *fp;
1100490778eSAugustin Cavalier
1110490778eSAugustin Cavalier fp = fopen(path, "r");
1120490778eSAugustin Cavalier if (fp == NULL)
1130490778eSAugustin Cavalier return -errno;
1140490778eSAugustin Cavalier if (fgets(line, max_bytes, fp) == NULL) {
1150490778eSAugustin Cavalier int ret = -EIO; /* fgets doesn't set errno */
1160490778eSAugustin Cavalier fclose(fp);
1170490778eSAugustin Cavalier return ret;
1180490778eSAugustin Cavalier }
1190490778eSAugustin Cavalier fclose (fp);
1200490778eSAugustin Cavalier return 0;
1210490778eSAugustin Cavalier }
1220490778eSAugustin Cavalier
read_u64(const char * path,u64 * n)1230490778eSAugustin Cavalier static int read_u64(const char *path, u64 *n)
1240490778eSAugustin Cavalier {
1250490778eSAugustin Cavalier char line[64];
1260490778eSAugustin Cavalier int ret;
1270490778eSAugustin Cavalier
1280490778eSAugustin Cavalier ret = read_line(path, line, sizeof line);
1290490778eSAugustin Cavalier if (ret)
1300490778eSAugustin Cavalier return ret;
1310490778eSAugustin Cavalier if (sscanf(line, "%" SCNu64, n) != 1)
1320490778eSAugustin Cavalier return -EINVAL;
1330490778eSAugustin Cavalier return 0;
1340490778eSAugustin Cavalier }
1350490778eSAugustin Cavalier
1360490778eSAugustin Cavalier /* Find discard limits for current backing device.
1370490778eSAugustin Cavalier */
fstrim_limits(ntfs_volume * vol,u64 * discard_alignment,u64 * discard_granularity,u64 * discard_max_bytes)1380490778eSAugustin Cavalier static int fstrim_limits(ntfs_volume *vol,
1390490778eSAugustin Cavalier u64 *discard_alignment,
1400490778eSAugustin Cavalier u64 *discard_granularity,
1410490778eSAugustin Cavalier u64 *discard_max_bytes)
1420490778eSAugustin Cavalier {
1430490778eSAugustin Cavalier struct stat statbuf;
144*9102cad6SAugustin Cavalier char path1[40]; /* holds "/sys/dev/block/%d:%d" */
145*9102cad6SAugustin Cavalier char path2[40 + sizeof(path1)]; /* less than 40 bytes more than path1 */
1460490778eSAugustin Cavalier int ret;
1470490778eSAugustin Cavalier
1480490778eSAugustin Cavalier /* Stat the backing device. Caller has ensured it is a block device. */
1490490778eSAugustin Cavalier if (stat(vol->dev->d_name, &statbuf) == -1) {
1500490778eSAugustin Cavalier ntfs_log_debug("fstrim_limits: could not stat %s\n",
1510490778eSAugustin Cavalier vol->dev->d_name);
1520490778eSAugustin Cavalier return -errno;
1530490778eSAugustin Cavalier }
1540490778eSAugustin Cavalier
1550490778eSAugustin Cavalier /* For whole devices,
1560490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/discard_alignment
1570490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/queue/discard_granularity
1580490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/queue/discard_max_bytes
1590490778eSAugustin Cavalier * will exist.
1600490778eSAugustin Cavalier * For partitions, we also need to check the parent device:
1610490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/../queue/discard_granularity
1620490778eSAugustin Cavalier * /sys/dev/block/MAJOR:MINOR/../queue/discard_max_bytes
1630490778eSAugustin Cavalier */
1640490778eSAugustin Cavalier snprintf(path1, sizeof path1, "/sys/dev/block/%d:%d",
1650490778eSAugustin Cavalier major(statbuf.st_rdev), minor(statbuf.st_rdev));
1660490778eSAugustin Cavalier
1670490778eSAugustin Cavalier snprintf(path2, sizeof path2, "%s/discard_alignment", path1);
1680490778eSAugustin Cavalier ret = read_u64(path2, discard_alignment);
1690490778eSAugustin Cavalier if (ret) {
1700490778eSAugustin Cavalier if (ret != -ENOENT)
1710490778eSAugustin Cavalier return ret;
1720490778eSAugustin Cavalier else
1730490778eSAugustin Cavalier /* We would expect this file to exist on all
1740490778eSAugustin Cavalier * modern kernels. But for the sake of very
1750490778eSAugustin Cavalier * old kernels:
1760490778eSAugustin Cavalier */
1770490778eSAugustin Cavalier goto not_found;
1780490778eSAugustin Cavalier }
1790490778eSAugustin Cavalier
1800490778eSAugustin Cavalier snprintf(path2, sizeof path2, "%s/queue/discard_granularity", path1);
1810490778eSAugustin Cavalier ret = read_u64(path2, discard_granularity);
1820490778eSAugustin Cavalier if (ret) {
1830490778eSAugustin Cavalier if (ret != -ENOENT)
1840490778eSAugustin Cavalier return ret;
1850490778eSAugustin Cavalier else {
1860490778eSAugustin Cavalier snprintf(path2, sizeof path2,
1870490778eSAugustin Cavalier "%s/../queue/discard_granularity", path1);
1880490778eSAugustin Cavalier ret = read_u64(path2, discard_granularity);
1890490778eSAugustin Cavalier if (ret) {
1900490778eSAugustin Cavalier if (ret != -ENOENT)
1910490778eSAugustin Cavalier return ret;
1920490778eSAugustin Cavalier else
1930490778eSAugustin Cavalier goto not_found;
1940490778eSAugustin Cavalier }
1950490778eSAugustin Cavalier }
1960490778eSAugustin Cavalier }
1970490778eSAugustin Cavalier
1980490778eSAugustin Cavalier snprintf(path2, sizeof path2, "%s/queue/discard_max_bytes", path1);
1990490778eSAugustin Cavalier ret = read_u64(path2, discard_max_bytes);
2000490778eSAugustin Cavalier if (ret) {
2010490778eSAugustin Cavalier if (ret != -ENOENT)
2020490778eSAugustin Cavalier return ret;
2030490778eSAugustin Cavalier else {
2040490778eSAugustin Cavalier snprintf(path2, sizeof path2,
2050490778eSAugustin Cavalier "%s/../queue/discard_max_bytes", path1);
2060490778eSAugustin Cavalier ret = read_u64(path2, discard_max_bytes);
2070490778eSAugustin Cavalier if (ret) {
2080490778eSAugustin Cavalier if (ret != -ENOENT)
2090490778eSAugustin Cavalier return ret;
2100490778eSAugustin Cavalier else
2110490778eSAugustin Cavalier goto not_found;
2120490778eSAugustin Cavalier }
2130490778eSAugustin Cavalier }
2140490778eSAugustin Cavalier }
2150490778eSAugustin Cavalier
2160490778eSAugustin Cavalier return 0;
2170490778eSAugustin Cavalier
2180490778eSAugustin Cavalier not_found:
2190490778eSAugustin Cavalier /* If we reach here then we didn't find the device. This is
2200490778eSAugustin Cavalier * not an error, but set discard_max_bytes = 0 to indicate
2210490778eSAugustin Cavalier * that discard is not available.
2220490778eSAugustin Cavalier */
2230490778eSAugustin Cavalier *discard_alignment = 0;
2240490778eSAugustin Cavalier *discard_granularity = 0;
2250490778eSAugustin Cavalier *discard_max_bytes = 0;
2260490778eSAugustin Cavalier return 0;
2270490778eSAugustin Cavalier }
2280490778eSAugustin Cavalier
align_up(ntfs_volume * vol,LCN lcn,u64 granularity)229*9102cad6SAugustin Cavalier static inline LCN align_up(ntfs_volume *vol, LCN lcn, u64 granularity)
230*9102cad6SAugustin Cavalier {
231*9102cad6SAugustin Cavalier u64 aligned;
232*9102cad6SAugustin Cavalier
233*9102cad6SAugustin Cavalier aligned = (lcn << vol->cluster_size_bits) + granularity - 1;
234*9102cad6SAugustin Cavalier aligned -= aligned % granularity;
235*9102cad6SAugustin Cavalier return (aligned >> vol->cluster_size_bits);
236*9102cad6SAugustin Cavalier }
237*9102cad6SAugustin Cavalier
align_down(ntfs_volume * vol,u64 count,u64 granularity)238*9102cad6SAugustin Cavalier static inline u64 align_down(ntfs_volume *vol, u64 count, u64 granularity)
239*9102cad6SAugustin Cavalier {
240*9102cad6SAugustin Cavalier u64 aligned;
241*9102cad6SAugustin Cavalier
242*9102cad6SAugustin Cavalier aligned = count << vol->cluster_size_bits;
243*9102cad6SAugustin Cavalier aligned -= aligned % granularity;
244*9102cad6SAugustin Cavalier return (aligned >> vol->cluster_size_bits);
245*9102cad6SAugustin Cavalier }
246*9102cad6SAugustin Cavalier
2470490778eSAugustin Cavalier #define FSTRIM_BUFSIZ 4096
2480490778eSAugustin Cavalier
2490490778eSAugustin Cavalier /* Trim the filesystem.
2500490778eSAugustin Cavalier *
2510490778eSAugustin Cavalier * Free blocks between 'start' and 'start+len-1' (both byte offsets)
2520490778eSAugustin Cavalier * are found and TRIM requests are sent to the block device. 'minlen'
2530490778eSAugustin Cavalier * is the minimum continguous free range to discard.
2540490778eSAugustin Cavalier */
fstrim(ntfs_volume * vol,void * data,u64 * trimmed)2550490778eSAugustin Cavalier static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
2560490778eSAugustin Cavalier {
2570490778eSAugustin Cavalier struct fstrim_range *range = data;
2580490778eSAugustin Cavalier u64 start = range->start;
2590490778eSAugustin Cavalier u64 len = range->len;
2600490778eSAugustin Cavalier u64 minlen = range->minlen;
2610490778eSAugustin Cavalier u64 discard_alignment, discard_granularity, discard_max_bytes;
2620490778eSAugustin Cavalier u8 *buf = NULL;
2630490778eSAugustin Cavalier LCN start_buf;
2640490778eSAugustin Cavalier int ret;
2650490778eSAugustin Cavalier
2660490778eSAugustin Cavalier ntfs_log_debug("fstrim: start=%llu len=%llu minlen=%llu\n",
2670490778eSAugustin Cavalier (unsigned long long) start,
2680490778eSAugustin Cavalier (unsigned long long) len,
2690490778eSAugustin Cavalier (unsigned long long) minlen);
2700490778eSAugustin Cavalier
2710490778eSAugustin Cavalier *trimmed = 0;
2720490778eSAugustin Cavalier
2730490778eSAugustin Cavalier /* Fail if user tries to use the fstrim -o/-l/-m options.
2740490778eSAugustin Cavalier * XXX We could fix these limitations in future.
2750490778eSAugustin Cavalier */
2760490778eSAugustin Cavalier if (start != 0 || len != (uint64_t)-1) {
277*9102cad6SAugustin Cavalier ntfs_log_error("fstrim: setting start or length is not supported\n");
2780490778eSAugustin Cavalier return -EINVAL;
2790490778eSAugustin Cavalier }
2800490778eSAugustin Cavalier if (minlen > vol->cluster_size) {
281*9102cad6SAugustin Cavalier ntfs_log_error("fstrim: minlen > cluster size is not supported\n");
2820490778eSAugustin Cavalier return -EINVAL;
2830490778eSAugustin Cavalier }
2840490778eSAugustin Cavalier
2850490778eSAugustin Cavalier /* Only block devices are supported. It would be possible to
2860490778eSAugustin Cavalier * support backing files (ie. without using loop) but the
2870490778eSAugustin Cavalier * ioctls used to punch holes in files are completely
2880490778eSAugustin Cavalier * different.
2890490778eSAugustin Cavalier */
2900490778eSAugustin Cavalier if (!NDevBlock(vol->dev)) {
291*9102cad6SAugustin Cavalier ntfs_log_error("fstrim: not supported for non-block-device\n");
2920490778eSAugustin Cavalier return -EOPNOTSUPP;
2930490778eSAugustin Cavalier }
2940490778eSAugustin Cavalier
2950490778eSAugustin Cavalier ret = fstrim_limits(vol, &discard_alignment,
2960490778eSAugustin Cavalier &discard_granularity, &discard_max_bytes);
2970490778eSAugustin Cavalier if (ret)
2980490778eSAugustin Cavalier return ret;
2990490778eSAugustin Cavalier if (discard_alignment != 0) {
300*9102cad6SAugustin Cavalier ntfs_log_error("fstrim: backing device is not aligned for discards\n");
3010490778eSAugustin Cavalier return -EOPNOTSUPP;
3020490778eSAugustin Cavalier }
303*9102cad6SAugustin Cavalier
3040490778eSAugustin Cavalier if (discard_max_bytes == 0) {
305*9102cad6SAugustin Cavalier ntfs_log_error("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
3060490778eSAugustin Cavalier return -EOPNOTSUPP;
3070490778eSAugustin Cavalier }
3080490778eSAugustin Cavalier
3090490778eSAugustin Cavalier /* Sync the device before doing anything. */
3100490778eSAugustin Cavalier ret = ntfs_device_sync(vol->dev);
3110490778eSAugustin Cavalier if (ret)
3120490778eSAugustin Cavalier return ret;
3130490778eSAugustin Cavalier
3140490778eSAugustin Cavalier /* Read through the bitmap. */
3150490778eSAugustin Cavalier buf = ntfs_malloc(FSTRIM_BUFSIZ);
3160490778eSAugustin Cavalier if (buf == NULL)
3170490778eSAugustin Cavalier return -errno;
3180490778eSAugustin Cavalier for (start_buf = 0; start_buf < vol->nr_clusters;
3190490778eSAugustin Cavalier start_buf += FSTRIM_BUFSIZ * 8) {
3200490778eSAugustin Cavalier s64 count;
3210490778eSAugustin Cavalier s64 br;
3220490778eSAugustin Cavalier LCN end_buf, start_lcn;
3230490778eSAugustin Cavalier
3240490778eSAugustin Cavalier /* start_buf is LCN of first cluster in the current buffer.
3250490778eSAugustin Cavalier * end_buf is LCN of last cluster + 1 in the current buffer.
3260490778eSAugustin Cavalier */
3270490778eSAugustin Cavalier end_buf = start_buf + FSTRIM_BUFSIZ*8;
3280490778eSAugustin Cavalier if (end_buf > vol->nr_clusters)
3290490778eSAugustin Cavalier end_buf = vol->nr_clusters;
3300490778eSAugustin Cavalier count = (end_buf - start_buf) / 8;
3310490778eSAugustin Cavalier
3320490778eSAugustin Cavalier br = ntfs_attr_pread(vol->lcnbmp_na, start_buf/8, count, buf);
3330490778eSAugustin Cavalier if (br != count) {
3340490778eSAugustin Cavalier if (br >= 0)
3350490778eSAugustin Cavalier ret = -EIO;
3360490778eSAugustin Cavalier else
3370490778eSAugustin Cavalier ret = -errno;
3380490778eSAugustin Cavalier goto free_out;
3390490778eSAugustin Cavalier }
3400490778eSAugustin Cavalier
3410490778eSAugustin Cavalier /* Trim the clusters in large as possible blocks, but
342*9102cad6SAugustin Cavalier * not larger than discard_max_bytes, and compatible
343*9102cad6SAugustin Cavalier * with the supported trim granularity.
3440490778eSAugustin Cavalier */
3450490778eSAugustin Cavalier for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) {
3460490778eSAugustin Cavalier if (!ntfs_bit_get(buf, start_lcn-start_buf)) {
3470490778eSAugustin Cavalier LCN end_lcn;
348*9102cad6SAugustin Cavalier LCN aligned_lcn;
349*9102cad6SAugustin Cavalier u64 aligned_count;
3500490778eSAugustin Cavalier
3510490778eSAugustin Cavalier /* Cluster 'start_lcn' is not in use,
3520490778eSAugustin Cavalier * find end of this run.
3530490778eSAugustin Cavalier */
3540490778eSAugustin Cavalier end_lcn = start_lcn+1;
3550490778eSAugustin Cavalier while (end_lcn < end_buf &&
3560490778eSAugustin Cavalier (u64) (end_lcn-start_lcn) << vol->cluster_size_bits
3570490778eSAugustin Cavalier < discard_max_bytes &&
3580490778eSAugustin Cavalier !ntfs_bit_get(buf, end_lcn-start_buf))
3590490778eSAugustin Cavalier end_lcn++;
360*9102cad6SAugustin Cavalier aligned_lcn = align_up(vol, start_lcn,
361*9102cad6SAugustin Cavalier discard_granularity);
362*9102cad6SAugustin Cavalier if (aligned_lcn >= end_lcn)
363*9102cad6SAugustin Cavalier aligned_count = 0;
364*9102cad6SAugustin Cavalier else {
365*9102cad6SAugustin Cavalier aligned_count =
366*9102cad6SAugustin Cavalier align_down(vol,
367*9102cad6SAugustin Cavalier end_lcn - aligned_lcn,
368*9102cad6SAugustin Cavalier discard_granularity);
369*9102cad6SAugustin Cavalier }
370*9102cad6SAugustin Cavalier if (aligned_count) {
3710490778eSAugustin Cavalier ret = fstrim_clusters(vol,
372*9102cad6SAugustin Cavalier aligned_lcn, aligned_count);
3730490778eSAugustin Cavalier if (ret)
3740490778eSAugustin Cavalier goto free_out;
3750490778eSAugustin Cavalier
376*9102cad6SAugustin Cavalier *trimmed += aligned_count
3770490778eSAugustin Cavalier << vol->cluster_size_bits;
378*9102cad6SAugustin Cavalier }
3790490778eSAugustin Cavalier start_lcn = end_lcn-1;
3800490778eSAugustin Cavalier }
3810490778eSAugustin Cavalier }
3820490778eSAugustin Cavalier }
3830490778eSAugustin Cavalier
3840490778eSAugustin Cavalier ret = 0;
3850490778eSAugustin Cavalier free_out:
3860490778eSAugustin Cavalier free(buf);
3870490778eSAugustin Cavalier return ret;
3880490778eSAugustin Cavalier }
3890490778eSAugustin Cavalier
3900490778eSAugustin Cavalier #endif /* FITRIM && BLKDISCARD */
3910490778eSAugustin Cavalier
ntfs_ioctl(ntfs_inode * ni,unsigned long cmd,void * arg,unsigned int flags,void * data)392*9102cad6SAugustin Cavalier int ntfs_ioctl(ntfs_inode *ni, unsigned long cmd,
393*9102cad6SAugustin Cavalier void *arg __attribute__((unused)),
3940490778eSAugustin Cavalier unsigned int flags __attribute__((unused)), void *data)
3950490778eSAugustin Cavalier {
3960490778eSAugustin Cavalier int ret = 0;
3970490778eSAugustin Cavalier
3980490778eSAugustin Cavalier switch (cmd) {
3990490778eSAugustin Cavalier #if defined(FITRIM) && defined(BLKDISCARD)
4000490778eSAugustin Cavalier case FITRIM:
4010490778eSAugustin Cavalier if (!ni || !data)
4020490778eSAugustin Cavalier ret = -EINVAL;
4030490778eSAugustin Cavalier else {
4040490778eSAugustin Cavalier u64 trimmed;
4050490778eSAugustin Cavalier struct fstrim_range *range = (struct fstrim_range*)data;
4060490778eSAugustin Cavalier
4070490778eSAugustin Cavalier ret = fstrim(ni->vol, data, &trimmed);
4080490778eSAugustin Cavalier range->len = trimmed;
4090490778eSAugustin Cavalier }
4100490778eSAugustin Cavalier break;
4110490778eSAugustin Cavalier #else
4120490778eSAugustin Cavalier #warning Trimming not supported : FITRIM or BLKDISCARD not defined
4130490778eSAugustin Cavalier #endif
4140490778eSAugustin Cavalier default :
4150490778eSAugustin Cavalier ret = -EINVAL;
4160490778eSAugustin Cavalier break;
4170490778eSAugustin Cavalier }
4180490778eSAugustin Cavalier return (ret);
4190490778eSAugustin Cavalier }
420