mirror of
https://github.com/fail0verflow/switch-linux.git
synced 2025-05-04 02:34:21 -04:00
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>
This commit is contained in:
parent
9abea2d64c
commit
a27b5b97d6
5 changed files with 128 additions and 0 deletions
|
@ -484,3 +484,98 @@ struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *a
|
||||||
a->btree.first_free = cpu_to_le16(8);
|
a->btree.first_free = cpu_to_le16(8);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned find_run(__le32 *bmp, unsigned *idx)
|
||||||
|
{
|
||||||
|
unsigned len;
|
||||||
|
while (tstbits(bmp, *idx, 1)) {
|
||||||
|
(*idx)++;
|
||||||
|
if (unlikely(*idx >= 0x4000))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
len = 1;
|
||||||
|
while (!tstbits(bmp, *idx + len, 1))
|
||||||
|
len++;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_trim(struct super_block *s, secno start, unsigned len, secno limit_start, secno limit_end, unsigned minlen, unsigned *result)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
secno end;
|
||||||
|
if (fatal_signal_pending(current))
|
||||||
|
return -EINTR;
|
||||||
|
end = start + len;
|
||||||
|
if (start < limit_start)
|
||||||
|
start = limit_start;
|
||||||
|
if (end > limit_end)
|
||||||
|
end = limit_end;
|
||||||
|
if (start >= end)
|
||||||
|
return 0;
|
||||||
|
if (end - start < minlen)
|
||||||
|
return 0;
|
||||||
|
err = sb_issue_discard(s, start, end - start, GFP_NOFS, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
*result += end - start;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hpfs_trim_fs(struct super_block *s, u64 start, u64 end, u64 minlen, unsigned *result)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
||||||
|
unsigned idx, len, start_bmp, end_bmp;
|
||||||
|
__le32 *bmp;
|
||||||
|
struct quad_buffer_head qbh;
|
||||||
|
|
||||||
|
*result = 0;
|
||||||
|
if (!end || end > sbi->sb_fs_size)
|
||||||
|
end = sbi->sb_fs_size;
|
||||||
|
if (start >= sbi->sb_fs_size)
|
||||||
|
return 0;
|
||||||
|
if (minlen > 0x4000)
|
||||||
|
return 0;
|
||||||
|
if (start < sbi->sb_dirband_start + sbi->sb_dirband_size && end > sbi->sb_dirband_start) {
|
||||||
|
hpfs_lock(s);
|
||||||
|
if (s->s_flags & MS_RDONLY) {
|
||||||
|
err = -EROFS;
|
||||||
|
goto unlock_1;
|
||||||
|
}
|
||||||
|
if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
|
||||||
|
err = -EIO;
|
||||||
|
goto unlock_1;
|
||||||
|
}
|
||||||
|
idx = 0;
|
||||||
|
while ((len = find_run(bmp, &idx)) && !err) {
|
||||||
|
err = do_trim(s, sbi->sb_dirband_start + idx * 4, len * 4, start, end, minlen, result);
|
||||||
|
idx += len;
|
||||||
|
}
|
||||||
|
hpfs_brelse4(&qbh);
|
||||||
|
unlock_1:
|
||||||
|
hpfs_unlock(s);
|
||||||
|
}
|
||||||
|
start_bmp = start >> 14;
|
||||||
|
end_bmp = (end + 0x3fff) >> 14;
|
||||||
|
while (start_bmp < end_bmp && !err) {
|
||||||
|
hpfs_lock(s);
|
||||||
|
if (s->s_flags & MS_RDONLY) {
|
||||||
|
err = -EROFS;
|
||||||
|
goto unlock_2;
|
||||||
|
}
|
||||||
|
if (!(bmp = hpfs_map_bitmap(s, start_bmp, &qbh, "trim"))) {
|
||||||
|
err = -EIO;
|
||||||
|
goto unlock_2;
|
||||||
|
}
|
||||||
|
idx = 0;
|
||||||
|
while ((len = find_run(bmp, &idx)) && !err) {
|
||||||
|
err = do_trim(s, (start_bmp << 14) + idx, len, start, end, minlen, result);
|
||||||
|
idx += len;
|
||||||
|
}
|
||||||
|
hpfs_brelse4(&qbh);
|
||||||
|
unlock_2:
|
||||||
|
hpfs_unlock(s);
|
||||||
|
start_bmp++;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
|
@ -327,4 +327,5 @@ const struct file_operations hpfs_dir_ops =
|
||||||
.iterate = hpfs_readdir,
|
.iterate = hpfs_readdir,
|
||||||
.release = hpfs_dir_release,
|
.release = hpfs_dir_release,
|
||||||
.fsync = hpfs_file_fsync,
|
.fsync = hpfs_file_fsync,
|
||||||
|
.unlocked_ioctl = hpfs_ioctl,
|
||||||
};
|
};
|
||||||
|
|
|
@ -203,6 +203,7 @@ const struct file_operations hpfs_file_ops =
|
||||||
.release = hpfs_file_release,
|
.release = hpfs_file_release,
|
||||||
.fsync = hpfs_file_fsync,
|
.fsync = hpfs_file_fsync,
|
||||||
.splice_read = generic_file_splice_read,
|
.splice_read = generic_file_splice_read,
|
||||||
|
.unlocked_ioctl = hpfs_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct inode_operations hpfs_file_iops =
|
const struct inode_operations hpfs_file_iops =
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/buffer_head.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/blkdev.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#include "hpfs.h"
|
#include "hpfs.h"
|
||||||
|
@ -200,6 +202,7 @@ void hpfs_free_dnode(struct super_block *, secno);
|
||||||
struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *);
|
struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *);
|
||||||
struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **);
|
struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **);
|
||||||
struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **);
|
struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **);
|
||||||
|
int hpfs_trim_fs(struct super_block *, u64, u64, u64, unsigned *);
|
||||||
|
|
||||||
/* anode.c */
|
/* anode.c */
|
||||||
|
|
||||||
|
@ -318,6 +321,7 @@ __printf(2, 3)
|
||||||
void hpfs_error(struct super_block *, const char *, ...);
|
void hpfs_error(struct super_block *, const char *, ...);
|
||||||
int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
|
int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
|
||||||
unsigned hpfs_get_free_dnodes(struct super_block *);
|
unsigned hpfs_get_free_dnodes(struct super_block *);
|
||||||
|
long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* local time (HPFS) to GMT (Unix)
|
* local time (HPFS) to GMT (Unix)
|
||||||
|
|
|
@ -196,6 +196,33 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
switch (cmd) {
|
||||||
|
case FITRIM: {
|
||||||
|
struct fstrim_range range;
|
||||||
|
secno n_trimmed;
|
||||||
|
int r;
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
return -EPERM;
|
||||||
|
if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range)))
|
||||||
|
return -EFAULT;
|
||||||
|
r = hpfs_trim_fs(file_inode(file)->i_sb, range.start >> 9, (range.start + range.len) >> 9, (range.minlen + 511) >> 9, &n_trimmed);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
range.len = (u64)n_trimmed << 9;
|
||||||
|
if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range)))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct kmem_cache * hpfs_inode_cachep;
|
static struct kmem_cache * hpfs_inode_cachep;
|
||||||
|
|
||||||
static struct inode *hpfs_alloc_inode(struct super_block *sb)
|
static struct inode *hpfs_alloc_inode(struct super_block *sb)
|
||||||
|
|
Loading…
Add table
Reference in a new issue