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; |
