diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-09 16:35:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-09 16:35:39 -0400 |
commit | c4b5fd3fb2058b650447372472ad24e2a989f9f6 (patch) | |
tree | 5fcba186fac4d108c64061c48f10a755b3310f8d | |
parent | 4c0a9f7458dabf2b8cb9987c863e335480a22b67 (diff) | |
parent | a28e4b2b18ccb90df402da3f21e1a83c9d4f8ec1 (diff) |
Merge branch 'hpfs-patches' (patches from Mikulas Patocka)
Merge hpfs updates from Mikulas Patocka.
Mainly fstrim support, with some minor other cleanups.
These were actually sent during the merge window, but I wanted to wait
for the FSTRIM compat handling cleanup before applying them. Mikulas
sent that earlier today.
* emailed patches from Mikulas Patocka <mikulas@twibright.com>:
hpfs: hpfs_error: Remove static buffer, use vsprintf extension %pV instead
hpfs: kstrdup() out of memory handling
hpfs: Remove unessary cast
hpfs: add fstrim support
-rw-r--r-- | fs/hpfs/alloc.c | 95 | ||||
-rw-r--r-- | fs/hpfs/dir.c | 1 | ||||
-rw-r--r-- | fs/hpfs/file.c | 1 | ||||
-rw-r--r-- | fs/hpfs/hpfs_fn.h | 4 | ||||
-rw-r--r-- | fs/hpfs/super.c | 47 |
5 files changed, 141 insertions, 7 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 | |||
488 | static 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 | |||
502 | static 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 | |||
524 | int 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); | ||
555 | unlock_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); | ||
576 | unlock_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 | ||
208 | const struct inode_operations hpfs_file_iops = | 209 | const 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); | |||
200 | struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *); | 202 | struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *); |
201 | struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **); | 203 | struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **); |
202 | struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **); | 204 | struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **); |
205 | int 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) | |||
318 | void hpfs_error(struct super_block *, const char *, ...); | 321 | void hpfs_error(struct super_block *, const char *, ...); |
319 | int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); | 322 | int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); |
320 | unsigned hpfs_get_free_dnodes(struct super_block *); | 323 | unsigned hpfs_get_free_dnodes(struct super_block *); |
324 | long 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..68a9bed05628 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c | |||
@@ -52,17 +52,20 @@ static void unmark_dirty(struct super_block *s) | |||
52 | } | 52 | } |
53 | 53 | ||
54 | /* Filesystem error... */ | 54 | /* Filesystem error... */ |
55 | static char err_buf[1024]; | ||
56 | |||
57 | void hpfs_error(struct super_block *s, const char *fmt, ...) | 55 | void hpfs_error(struct super_block *s, const char *fmt, ...) |
58 | { | 56 | { |
57 | struct va_format vaf; | ||
59 | va_list args; | 58 | va_list args; |
60 | 59 | ||
61 | va_start(args, fmt); | 60 | va_start(args, fmt); |
62 | vsnprintf(err_buf, sizeof(err_buf), fmt, args); | 61 | |
62 | vaf.fmt = fmt; | ||
63 | vaf.va = &args; | ||
64 | |||
65 | pr_err("filesystem error: %pV", &vaf); | ||
66 | |||
63 | va_end(args); | 67 | va_end(args); |
64 | 68 | ||
65 | pr_err("filesystem error: %s", err_buf); | ||
66 | if (!hpfs_sb(s)->sb_was_error) { | 69 | if (!hpfs_sb(s)->sb_was_error) { |
67 | if (hpfs_sb(s)->sb_err == 2) { | 70 | if (hpfs_sb(s)->sb_err == 2) { |
68 | pr_cont("; crashing the system because you wanted it\n"); | 71 | pr_cont("; crashing the system because you wanted it\n"); |
@@ -196,12 +199,39 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
196 | return 0; | 199 | return 0; |
197 | } | 200 | } |
198 | 201 | ||
202 | |||
203 | long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg) | ||
204 | { | ||
205 | switch (cmd) { | ||
206 | case FITRIM: { | ||
207 | struct fstrim_range range; | ||
208 | secno n_trimmed; | ||
209 | int r; | ||
210 | if (!capable(CAP_SYS_ADMIN)) | ||
211 | return -EPERM; | ||
212 | if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range))) | ||
213 | return -EFAULT; | ||
214 | r = hpfs_trim_fs(file_inode(file)->i_sb, range.start >> 9, (range.start + range.len) >> 9, (range.minlen + 511) >> 9, &n_trimmed); | ||
215 | if (r) | ||
216 | return r; | ||
217 | range.len = (u64)n_trimmed << 9; | ||
218 | if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range))) | ||
219 | return -EFAULT; | ||
220 | return 0; | ||
221 | } | ||
222 | default: { | ||
223 | return -ENOIOCTLCMD; | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | |||
199 | static struct kmem_cache * hpfs_inode_cachep; | 229 | static struct kmem_cache * hpfs_inode_cachep; |
200 | 230 | ||
201 | static struct inode *hpfs_alloc_inode(struct super_block *sb) | 231 | static struct inode *hpfs_alloc_inode(struct super_block *sb) |
202 | { | 232 | { |
203 | struct hpfs_inode_info *ei; | 233 | struct hpfs_inode_info *ei; |
204 | ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS); | 234 | ei = kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS); |
205 | if (!ei) | 235 | if (!ei) |
206 | return NULL; | 236 | return NULL; |
207 | ei->vfs_inode.i_version = 1; | 237 | ei->vfs_inode.i_version = 1; |
@@ -424,11 +454,14 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) | |||
424 | int o; | 454 | int o; |
425 | struct hpfs_sb_info *sbi = hpfs_sb(s); | 455 | struct hpfs_sb_info *sbi = hpfs_sb(s); |
426 | char *new_opts = kstrdup(data, GFP_KERNEL); | 456 | char *new_opts = kstrdup(data, GFP_KERNEL); |
427 | 457 | ||
458 | if (!new_opts) | ||
459 | return -ENOMEM; | ||
460 | |||
428 | sync_filesystem(s); | 461 | sync_filesystem(s); |
429 | 462 | ||
430 | *flags |= MS_NOATIME; | 463 | *flags |= MS_NOATIME; |
431 | 464 | ||
432 | hpfs_lock(s); | 465 | hpfs_lock(s); |
433 | uid = sbi->sb_uid; gid = sbi->sb_gid; | 466 | uid = sbi->sb_uid; gid = sbi->sb_gid; |
434 | umask = 0777 & ~sbi->sb_mode; | 467 | umask = 0777 & ~sbi->sb_mode; |