Commit f9ba7179 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: fix blksize calculation
  fuse: fix stat call on 32 bit platforms
  fuse: optimize fallocate on permanent failure
  fuse: add FALLOCATE operation
  fuse: Convert to kstrtoul_from_user
parents 0b3e9f3f 203627bb
...@@ -75,19 +75,13 @@ static ssize_t fuse_conn_limit_write(struct file *file, const char __user *buf, ...@@ -75,19 +75,13 @@ static ssize_t fuse_conn_limit_write(struct file *file, const char __user *buf,
unsigned global_limit) unsigned global_limit)
{ {
unsigned long t; unsigned long t;
char tmp[32];
unsigned limit = (1 << 16) - 1; unsigned limit = (1 << 16) - 1;
int err; int err;
if (*ppos || count >= sizeof(tmp) - 1) if (*ppos)
return -EINVAL;
if (copy_from_user(tmp, buf, count))
return -EINVAL; return -EINVAL;
tmp[count] = '\0'; err = kstrtoul_from_user(buf, count, 0, &t);
err = strict_strtoul(tmp, 0, &t);
if (err) if (err)
return err; return err;
......
...@@ -775,6 +775,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, ...@@ -775,6 +775,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
struct kstat *stat) struct kstat *stat)
{ {
unsigned int blkbits;
stat->dev = inode->i_sb->s_dev; stat->dev = inode->i_sb->s_dev;
stat->ino = attr->ino; stat->ino = attr->ino;
stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
...@@ -790,7 +792,13 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, ...@@ -790,7 +792,13 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
stat->ctime.tv_nsec = attr->ctimensec; stat->ctime.tv_nsec = attr->ctimensec;
stat->size = attr->size; stat->size = attr->size;
stat->blocks = attr->blocks; stat->blocks = attr->blocks;
stat->blksize = (1 << inode->i_blkbits);
if (attr->blksize != 0)
blkbits = ilog2(attr->blksize);
else
blkbits = inode->i_sb->s_blocksize_bits;
stat->blksize = 1 << blkbits;
} }
static int fuse_do_getattr(struct inode *inode, struct kstat *stat, static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
...@@ -863,6 +871,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat, ...@@ -863,6 +871,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
if (stat) { if (stat) {
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
stat->mode = fi->orig_i_mode; stat->mode = fi->orig_i_mode;
stat->ino = fi->orig_ino;
} }
} }
......
...@@ -2173,6 +2173,44 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, ...@@ -2173,6 +2173,44 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
return ret; return ret;
} }
long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
loff_t length)
{
struct fuse_file *ff = file->private_data;
struct fuse_conn *fc = ff->fc;
struct fuse_req *req;
struct fuse_fallocate_in inarg = {
.fh = ff->fh,
.offset = offset,
.length = length,
.mode = mode
};
int err;
if (fc->no_fallocate)
return -EOPNOTSUPP;
req = fuse_get_req(fc);
if (IS_ERR(req))
return PTR_ERR(req);
req->in.h.opcode = FUSE_FALLOCATE;
req->in.h.nodeid = ff->nodeid;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
fuse_request_send(fc, req);
err = req->out.h.error;
if (err == -ENOSYS) {
fc->no_fallocate = 1;
err = -EOPNOTSUPP;
}
fuse_put_request(fc, req);
return err;
}
EXPORT_SYMBOL_GPL(fuse_file_fallocate);
static const struct file_operations fuse_file_operations = { static const struct file_operations fuse_file_operations = {
.llseek = fuse_file_llseek, .llseek = fuse_file_llseek,
.read = do_sync_read, .read = do_sync_read,
...@@ -2190,6 +2228,7 @@ static const struct file_operations fuse_file_operations = { ...@@ -2190,6 +2228,7 @@ static const struct file_operations fuse_file_operations = {
.unlocked_ioctl = fuse_file_ioctl, .unlocked_ioctl = fuse_file_ioctl,
.compat_ioctl = fuse_file_compat_ioctl, .compat_ioctl = fuse_file_compat_ioctl,
.poll = fuse_file_poll, .poll = fuse_file_poll,
.fallocate = fuse_file_fallocate,
}; };
static const struct file_operations fuse_direct_io_file_operations = { static const struct file_operations fuse_direct_io_file_operations = {
...@@ -2206,6 +2245,7 @@ static const struct file_operations fuse_direct_io_file_operations = { ...@@ -2206,6 +2245,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
.unlocked_ioctl = fuse_file_ioctl, .unlocked_ioctl = fuse_file_ioctl,
.compat_ioctl = fuse_file_compat_ioctl, .compat_ioctl = fuse_file_compat_ioctl,
.poll = fuse_file_poll, .poll = fuse_file_poll,
.fallocate = fuse_file_fallocate,
/* no splice_read */ /* no splice_read */
}; };
......
...@@ -82,6 +82,9 @@ struct fuse_inode { ...@@ -82,6 +82,9 @@ struct fuse_inode {
preserve the original mode */ preserve the original mode */
umode_t orig_i_mode; umode_t orig_i_mode;
/** 64 bit inode number */
u64 orig_ino;
/** Version of last attribute change */ /** Version of last attribute change */
u64 attr_version; u64 attr_version;
...@@ -478,6 +481,9 @@ struct fuse_conn { ...@@ -478,6 +481,9 @@ struct fuse_conn {
/** Are BSD file locking primitives not implemented by fs? */ /** Are BSD file locking primitives not implemented by fs? */
unsigned no_flock:1; unsigned no_flock:1;
/** Is fallocate not implemented by fs? */
unsigned no_fallocate:1;
/** The number of requests waiting for completion */ /** The number of requests waiting for completion */
atomic_t num_waiting; atomic_t num_waiting;
......
...@@ -91,6 +91,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) ...@@ -91,6 +91,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
fi->nlookup = 0; fi->nlookup = 0;
fi->attr_version = 0; fi->attr_version = 0;
fi->writectr = 0; fi->writectr = 0;
fi->orig_ino = 0;
INIT_LIST_HEAD(&fi->write_files); INIT_LIST_HEAD(&fi->write_files);
INIT_LIST_HEAD(&fi->queued_writes); INIT_LIST_HEAD(&fi->queued_writes);
INIT_LIST_HEAD(&fi->writepages); INIT_LIST_HEAD(&fi->writepages);
...@@ -139,6 +140,18 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) ...@@ -139,6 +140,18 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
return 0; return 0;
} }
/*
* ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
* so that it will fit.
*/
static ino_t fuse_squash_ino(u64 ino64)
{
ino_t ino = (ino_t) ino64;
if (sizeof(ino_t) < sizeof(u64))
ino ^= ino64 >> (sizeof(u64) - sizeof(ino_t)) * 8;
return ino;
}
void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid) u64 attr_valid)
{ {
...@@ -148,7 +161,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, ...@@ -148,7 +161,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
fi->attr_version = ++fc->attr_version; fi->attr_version = ++fc->attr_version;
fi->i_time = attr_valid; fi->i_time = attr_valid;
inode->i_ino = attr->ino; inode->i_ino = fuse_squash_ino(attr->ino);
inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
set_nlink(inode, attr->nlink); set_nlink(inode, attr->nlink);
inode->i_uid = attr->uid; inode->i_uid = attr->uid;
...@@ -174,6 +187,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, ...@@ -174,6 +187,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
fi->orig_i_mode = inode->i_mode; fi->orig_i_mode = inode->i_mode;
if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
inode->i_mode &= ~S_ISVTX; inode->i_mode &= ~S_ISVTX;
fi->orig_ino = attr->ino;
} }
void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
......
...@@ -54,6 +54,9 @@ ...@@ -54,6 +54,9 @@
* 7.18 * 7.18
* - add FUSE_IOCTL_DIR flag * - add FUSE_IOCTL_DIR flag
* - add FUSE_NOTIFY_DELETE * - add FUSE_NOTIFY_DELETE
*
* 7.19
* - add FUSE_FALLOCATE
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
...@@ -85,7 +88,7 @@ ...@@ -85,7 +88,7 @@
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 18 #define FUSE_KERNEL_MINOR_VERSION 19
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
...@@ -278,6 +281,7 @@ enum fuse_opcode { ...@@ -278,6 +281,7 @@ enum fuse_opcode {
FUSE_POLL = 40, FUSE_POLL = 40,
FUSE_NOTIFY_REPLY = 41, FUSE_NOTIFY_REPLY = 41,
FUSE_BATCH_FORGET = 42, FUSE_BATCH_FORGET = 42,
FUSE_FALLOCATE = 43,
/* CUSE specific operations */ /* CUSE specific operations */
CUSE_INIT = 4096, CUSE_INIT = 4096,
...@@ -571,6 +575,14 @@ struct fuse_notify_poll_wakeup_out { ...@@ -571,6 +575,14 @@ struct fuse_notify_poll_wakeup_out {
__u64 kh; __u64 kh;
}; };
struct fuse_fallocate_in {
__u64 fh;
__u64 offset;
__u64 length;
__u32 mode;
__u32 padding;
};
struct fuse_in_header { struct fuse_in_header {
__u32 len; __u32 len;
__u32 opcode; __u32 opcode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment