aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-07-09 16:35:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-07-09 16:35:39 -0400
commitc4b5fd3fb2058b650447372472ad24e2a989f9f6 (patch)
tree5fcba186fac4d108c64061c48f10a755b3310f8d
parent4c0a9f7458dabf2b8cb9987c863e335480a22b67 (diff)
parenta28e4b2b18ccb90df402da3f21e1a83c9d4f8ec1 (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.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.c47
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
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..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... */
55static char err_buf[1024];
56
57void hpfs_error(struct super_block *s, const char *fmt, ...) 55void 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
203long 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
199static struct kmem_cache * hpfs_inode_cachep; 229static struct kmem_cache * hpfs_inode_cachep;
200 230
201static struct inode *hpfs_alloc_inode(struct super_block *sb) 231static 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;