aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hpfs
diff options
context:
space:
mode:
authorMikulas Patocka <mikulas@twibright.com>2015-06-28 09:16:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-07-09 16:35:30 -0400
commita27b5b97d6fe91f55058ad8ac28a8768700201ab (patch)
tree84272380472c484455a662d17b0b544421a26fe2 /fs/hpfs
parent9abea2d64ce93b6909de7f83a7f681f572369708 (diff)
hpfs: add fstrim support
This patch adds support for fstrim to the HPFS filesystem. Signed-off-by: Mikulas Patocka <mikulas@twibright.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/hpfs')
-rw-r--r--fs/hpfs/alloc.c95
-rw-r--r--fs/hpfs/dir.c1
-rw-r--r--fs/hpfs/file.c1
-rw-r--r--fs/hpfs/hpfs_fn.h4
-rw-r--r--fs/hpfs/super.c27
5 files changed, 128 insertions, 0 deletions
diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c
index f005046e1591..d6a4b55d2ab0 100644
--- a/fs/hpfs/alloc.c
+++ b/fs/hpfs/alloc.c
@@ -484,3 +484,98 @@ struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *a
484 a->btree.first_free = cpu_to_le16(8); 484 a->btree.first_free = cpu_to_le16(8);
485 return a; 485 return a;
486} 486}
487
488static unsigned find_run(__le32 *bmp, unsigned *idx)
489{
490 unsigned len;
491 while (tstbits(bmp, *idx, 1)) {
492 (*idx)++;
493 if (unlikely(*idx >= 0x4000))
494 return 0;
495 }
496 len = 1;
497 while (!tstbits(bmp, *idx + len, 1))
498 len++;
499 return len;
500}
501
502static int do_trim(struct super_block *s, secno start, unsigned len, secno limit_start, secno limit_end, unsigned minlen, unsigned *result)
503{
504 int err;
505 secno end;
506 if (fatal_signal_pending(current))
507 return -EINTR;
508 end = start + len;
509 if (start < limit_start)
510 start = limit_start;
511 if (end > limit_end)
512 end = limit_end;
513 if (start >= end)
514 return 0;
515 if (end - start < minlen)
516 return 0;
517 err = sb_issue_discard(s, start, end - start, GFP_NOFS, 0);
518 if (err)
519 return err;
520 *result += end - start;
521 return 0;
522}
523
524int hpfs_trim_fs(struct super_block *s, u64 start, u64 end, u64 minlen, unsigned *result)
525{
526 int err = 0;
527 struct hpfs_sb_info *sbi = hpfs_sb(s);
528 unsigned idx, len, start_bmp, end_bmp;
529 __le32 *bmp;
530 struct quad_buffer_head qbh;
531
532 *result = 0;
533 if (!end || end > sbi->sb_fs_size)
534 end = sbi->sb_fs_size;
535 if (start >= sbi->sb_fs_size)
536 return 0;
537 if (minlen > 0x4000)
538 return 0;
539 if (start < sbi->sb_dirband_start + sbi->sb_dirband_size && end > sbi->sb_dirband_start) {
540 hpfs_lock(s);
541 if (s->s_flags & MS_RDONLY) {
542 err = -EROFS;
543 goto unlock_1;
544 }
545 if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
546 err = -EIO;
547 goto unlock_1;
548 }
549 idx = 0;
550 while ((len = find_run(bmp, &idx)) && !err) {
551 err = do_trim(s, sbi->sb_dirband_start + idx * 4, len * 4, start, end, minlen, result);
552 idx += len;
553 }
554 hpfs_brelse4(&qbh);
555unlock_1:
556 hpfs_unlock(s);
557 }
558 start_bmp = start >> 14;
559 end_bmp = (end + 0x3fff) >> 14;
560 while (start_bmp < end_bmp && !err) {
561 hpfs_lock(s);
562 if (s->s_flags & MS_RDONLY) {
563 err = -EROFS;
564 goto unlock_2;
565 }
566 if (!(bmp = hpfs_map_bitmap(s, start_bmp, &qbh, "trim"))) {
567 err = -EIO;
568 goto unlock_2;
569 }
570 idx = 0;
571 while ((len = find_run(bmp, &idx)) && !err) {
572 err = do_trim(s, (start_bmp << 14) + idx, len, start, end, minlen, result);
573 idx += len;
574 }
575 hpfs_brelse4(&qbh);
576unlock_2:
577 hpfs_unlock(s);
578 start_bmp++;
579 }
580 return err;
581}
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 2a8e07425de0..dc540bfcee1d 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -327,4 +327,5 @@ const struct file_operations hpfs_dir_ops =
327 .iterate = hpfs_readdir, 327 .iterate = hpfs_readdir,
328 .release = hpfs_dir_release, 328 .release = hpfs_dir_release,
329 .fsync = hpfs_file_fsync, 329 .fsync = hpfs_file_fsync,
330 .unlocked_ioctl = hpfs_ioctl,
330}; 331};
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 6d8cfe9b52d6..7ca28d604bf7 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -203,6 +203,7 @@ const struct file_operations hpfs_file_ops =
203 .release = hpfs_file_release, 203 .release = hpfs_file_release,
204 .fsync = hpfs_file_fsync, 204 .fsync = hpfs_file_fsync,
205 .splice_read = generic_file_splice_read, 205 .splice_read = generic_file_splice_read,
206 .unlocked_ioctl = hpfs_ioctl,
206}; 207};
207 208
208const struct inode_operations hpfs_file_iops = 209const struct inode_operations hpfs_file_iops =
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index bb04b58d1d69..c4867b5116dd 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -18,6 +18,8 @@
18#include <linux/pagemap.h> 18#include <linux/pagemap.h>
19#include <linux/buffer_head.h> 19#include <linux/buffer_head.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/sched.h>
22#include <linux/blkdev.h>
21#include <asm/unaligned.h> 23#include <asm/unaligned.h>
22 24
23#include "hpfs.h" 25#include "hpfs.h"
@@ -200,6 +202,7 @@ void hpfs_free_dnode(struct super_block *, secno);
200struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *); 202struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *);
201struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **); 203struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **);
202struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **); 204struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **);
205int hpfs_trim_fs(struct super_block *, u64, u64, u64, unsigned *);
203 206
204/* anode.c */ 207/* anode.c */
205 208
@@ -318,6 +321,7 @@ __printf(2, 3)
318void hpfs_error(struct super_block *, const char *, ...); 321void hpfs_error(struct super_block *, const char *, ...);
319int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); 322int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
320unsigned hpfs_get_free_dnodes(struct super_block *); 323unsigned hpfs_get_free_dnodes(struct super_block *);
324long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg);
321 325
322/* 326/*
323 * local time (HPFS) to GMT (Unix) 327 * local time (HPFS) to GMT (Unix)
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 7cd00d3a7c9b..037e3e597ff4 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -196,6 +196,33 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
196 return 0; 196 return 0;
197} 197}
198 198
199
200long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg)
201{
202 switch (cmd) {
203 case FITRIM: {
204 struct fstrim_range range;
205 secno n_trimmed;
206 int r;
207 if (!capable(CAP_SYS_ADMIN))
208 return -EPERM;
209 if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range)))
210 return -EFAULT;
211 r = hpfs_trim_fs(file_inode(file)->i_sb, range.start >> 9, (range.start + range.len) >> 9, (range.minlen + 511) >> 9, &n_trimmed);
212 if (r)
213 return r;
214 range.len = (u64)n_trimmed << 9;
215 if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range)))
216 return -EFAULT;
217 return 0;
218 }
219 default: {
220 return -ENOIOCTLCMD;
221 }
222 }
223}
224
225
199static struct kmem_cache * hpfs_inode_cachep; 226static struct kmem_cache * hpfs_inode_cachep;
200 227
201static struct inode *hpfs_alloc_inode(struct super_block *sb) 228static struct inode *hpfs_alloc_inode(struct super_block *sb)