Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4b5fd3f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 4c0a9f74 a28e4b2b
Loading
Loading
Loading
Loading
+95 −0
Original line number Original line Diff line number Diff line
@@ -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;
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -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,
};
};
+1 −0
Original line number Original line Diff line number Diff line
@@ -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 =
+4 −0
Original line number Original line Diff line number Diff line
@@ -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)
+40 −7
Original line number Original line Diff line number Diff line
@@ -52,17 +52,20 @@ static void unmark_dirty(struct super_block *s)
}
}


/* Filesystem error... */
/* Filesystem error... */
static char err_buf[1024];

void hpfs_error(struct super_block *s, const char *fmt, ...)
void hpfs_error(struct super_block *s, const char *fmt, ...)
{
{
	struct va_format vaf;
	va_list args;
	va_list args;


	va_start(args, fmt);
	va_start(args, fmt);
	vsnprintf(err_buf, sizeof(err_buf), fmt, args);

	vaf.fmt = fmt;
	vaf.va = &args;

	pr_err("filesystem error: %pV", &vaf);

	va_end(args);
	va_end(args);


	pr_err("filesystem error: %s", err_buf);
	if (!hpfs_sb(s)->sb_was_error) {
	if (!hpfs_sb(s)->sb_was_error) {
		if (hpfs_sb(s)->sb_err == 2) {
		if (hpfs_sb(s)->sb_err == 2) {
			pr_cont("; crashing the system because you wanted it\n");
			pr_cont("; crashing the system because you wanted it\n");
@@ -196,12 +199,39 @@ 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)
{
{
	struct hpfs_inode_info *ei;
	struct hpfs_inode_info *ei;
	ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS);
	ei = kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS);
	if (!ei)
	if (!ei)
		return NULL;
		return NULL;
	ei->vfs_inode.i_version = 1;
	ei->vfs_inode.i_version = 1;
@@ -425,6 +455,9 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
	struct hpfs_sb_info *sbi = hpfs_sb(s);
	struct hpfs_sb_info *sbi = hpfs_sb(s);
	char *new_opts = kstrdup(data, GFP_KERNEL);
	char *new_opts = kstrdup(data, GFP_KERNEL);


	if (!new_opts)
		return -ENOMEM;

	sync_filesystem(s);
	sync_filesystem(s);


	*flags |= MS_NOATIME;
	*flags |= MS_NOATIME;