diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-05 13:11:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-05 13:11:11 -0400 |
commit | f9ba7179ce91fb77b2adf6eaab3676ab3a1f5a15 (patch) | |
tree | 2d02e7a4fd78083b78749d0c9c7466f0eb8e6f97 /fs | |
parent | 0b3e9f3f21c42d064f5f4088df4088e3d55755eb (diff) | |
parent | 203627bbc90377c509e32450c67c5d957ba2d989 (diff) |
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
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/control.c | 10 | ||||
-rw-r--r-- | fs/fuse/dir.c | 11 | ||||
-rw-r--r-- | fs/fuse/file.c | 40 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 6 | ||||
-rw-r--r-- | fs/fuse/inode.c | 17 |
5 files changed, 74 insertions, 10 deletions
diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 42593c587d48..03ff5b1eba93 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c | |||
@@ -75,19 +75,13 @@ static ssize_t fuse_conn_limit_write(struct file *file, const char __user *buf, | |||
75 | unsigned global_limit) | 75 | unsigned global_limit) |
76 | { | 76 | { |
77 | unsigned long t; | 77 | unsigned long t; |
78 | char tmp[32]; | ||
79 | unsigned limit = (1 << 16) - 1; | 78 | unsigned limit = (1 << 16) - 1; |
80 | int err; | 79 | int err; |
81 | 80 | ||
82 | if (*ppos || count >= sizeof(tmp) - 1) | 81 | if (*ppos) |
83 | return -EINVAL; | ||
84 | |||
85 | if (copy_from_user(tmp, buf, count)) | ||
86 | return -EINVAL; | 82 | return -EINVAL; |
87 | 83 | ||
88 | tmp[count] = '\0'; | 84 | err = kstrtoul_from_user(buf, count, 0, &t); |
89 | |||
90 | err = strict_strtoul(tmp, 0, &t); | ||
91 | if (err) | 85 | if (err) |
92 | return err; | 86 | return err; |
93 | 87 | ||
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index df5ac048dc74..334e0b18a014 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -775,6 +775,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, | |||
775 | static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, | 775 | static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, |
776 | struct kstat *stat) | 776 | struct kstat *stat) |
777 | { | 777 | { |
778 | unsigned int blkbits; | ||
779 | |||
778 | stat->dev = inode->i_sb->s_dev; | 780 | stat->dev = inode->i_sb->s_dev; |
779 | stat->ino = attr->ino; | 781 | stat->ino = attr->ino; |
780 | stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); | 782 | 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 | stat->ctime.tv_nsec = attr->ctimensec; | 792 | stat->ctime.tv_nsec = attr->ctimensec; |
791 | stat->size = attr->size; | 793 | stat->size = attr->size; |
792 | stat->blocks = attr->blocks; | 794 | stat->blocks = attr->blocks; |
793 | stat->blksize = (1 << inode->i_blkbits); | 795 | |
796 | if (attr->blksize != 0) | ||
797 | blkbits = ilog2(attr->blksize); | ||
798 | else | ||
799 | blkbits = inode->i_sb->s_blocksize_bits; | ||
800 | |||
801 | stat->blksize = 1 << blkbits; | ||
794 | } | 802 | } |
795 | 803 | ||
796 | static int fuse_do_getattr(struct inode *inode, struct kstat *stat, | 804 | 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 | if (stat) { | 871 | if (stat) { |
864 | generic_fillattr(inode, stat); | 872 | generic_fillattr(inode, stat); |
865 | stat->mode = fi->orig_i_mode; | 873 | stat->mode = fi->orig_i_mode; |
874 | stat->ino = fi->orig_ino; | ||
866 | } | 875 | } |
867 | } | 876 | } |
868 | 877 | ||
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 9562109d3a87..b321a688cde7 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -2173,6 +2173,44 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
2173 | return ret; | 2173 | return ret; |
2174 | } | 2174 | } |
2175 | 2175 | ||
2176 | long fuse_file_fallocate(struct file *file, int mode, loff_t offset, | ||
2177 | loff_t length) | ||
2178 | { | ||
2179 | struct fuse_file *ff = file->private_data; | ||
2180 | struct fuse_conn *fc = ff->fc; | ||
2181 | struct fuse_req *req; | ||
2182 | struct fuse_fallocate_in inarg = { | ||
2183 | .fh = ff->fh, | ||
2184 | .offset = offset, | ||
2185 | .length = length, | ||
2186 | .mode = mode | ||
2187 | }; | ||
2188 | int err; | ||
2189 | |||
2190 | if (fc->no_fallocate) | ||
2191 | return -EOPNOTSUPP; | ||
2192 | |||
2193 | req = fuse_get_req(fc); | ||
2194 | if (IS_ERR(req)) | ||
2195 | return PTR_ERR(req); | ||
2196 | |||
2197 | req->in.h.opcode = FUSE_FALLOCATE; | ||
2198 | req->in.h.nodeid = ff->nodeid; | ||
2199 | req->in.numargs = 1; | ||
2200 | req->in.args[0].size = sizeof(inarg); | ||
2201 | req->in.args[0].value = &inarg; | ||
2202 | fuse_request_send(fc, req); | ||
2203 | err = req->out.h.error; | ||
2204 | if (err == -ENOSYS) { | ||
2205 | fc->no_fallocate = 1; | ||
2206 | err = -EOPNOTSUPP; | ||
2207 | } | ||
2208 | fuse_put_request(fc, req); | ||
2209 | |||
2210 | return err; | ||
2211 | } | ||
2212 | EXPORT_SYMBOL_GPL(fuse_file_fallocate); | ||
2213 | |||
2176 | static const struct file_operations fuse_file_operations = { | 2214 | static const struct file_operations fuse_file_operations = { |
2177 | .llseek = fuse_file_llseek, | 2215 | .llseek = fuse_file_llseek, |
2178 | .read = do_sync_read, | 2216 | .read = do_sync_read, |
@@ -2190,6 +2228,7 @@ static const struct file_operations fuse_file_operations = { | |||
2190 | .unlocked_ioctl = fuse_file_ioctl, | 2228 | .unlocked_ioctl = fuse_file_ioctl, |
2191 | .compat_ioctl = fuse_file_compat_ioctl, | 2229 | .compat_ioctl = fuse_file_compat_ioctl, |
2192 | .poll = fuse_file_poll, | 2230 | .poll = fuse_file_poll, |
2231 | .fallocate = fuse_file_fallocate, | ||
2193 | }; | 2232 | }; |
2194 | 2233 | ||
2195 | static const struct file_operations fuse_direct_io_file_operations = { | 2234 | 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 | .unlocked_ioctl = fuse_file_ioctl, | 2245 | .unlocked_ioctl = fuse_file_ioctl, |
2207 | .compat_ioctl = fuse_file_compat_ioctl, | 2246 | .compat_ioctl = fuse_file_compat_ioctl, |
2208 | .poll = fuse_file_poll, | 2247 | .poll = fuse_file_poll, |
2248 | .fallocate = fuse_file_fallocate, | ||
2209 | /* no splice_read */ | 2249 | /* no splice_read */ |
2210 | }; | 2250 | }; |
2211 | 2251 | ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 572cefc78012..771fb6322c07 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -82,6 +82,9 @@ struct fuse_inode { | |||
82 | preserve the original mode */ | 82 | preserve the original mode */ |
83 | umode_t orig_i_mode; | 83 | umode_t orig_i_mode; |
84 | 84 | ||
85 | /** 64 bit inode number */ | ||
86 | u64 orig_ino; | ||
87 | |||
85 | /** Version of last attribute change */ | 88 | /** Version of last attribute change */ |
86 | u64 attr_version; | 89 | u64 attr_version; |
87 | 90 | ||
@@ -478,6 +481,9 @@ struct fuse_conn { | |||
478 | /** Are BSD file locking primitives not implemented by fs? */ | 481 | /** Are BSD file locking primitives not implemented by fs? */ |
479 | unsigned no_flock:1; | 482 | unsigned no_flock:1; |
480 | 483 | ||
484 | /** Is fallocate not implemented by fs? */ | ||
485 | unsigned no_fallocate:1; | ||
486 | |||
481 | /** The number of requests waiting for completion */ | 487 | /** The number of requests waiting for completion */ |
482 | atomic_t num_waiting; | 488 | atomic_t num_waiting; |
483 | 489 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 42678a33b7bb..1cd61652018c 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -91,6 +91,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
91 | fi->nlookup = 0; | 91 | fi->nlookup = 0; |
92 | fi->attr_version = 0; | 92 | fi->attr_version = 0; |
93 | fi->writectr = 0; | 93 | fi->writectr = 0; |
94 | fi->orig_ino = 0; | ||
94 | INIT_LIST_HEAD(&fi->write_files); | 95 | INIT_LIST_HEAD(&fi->write_files); |
95 | INIT_LIST_HEAD(&fi->queued_writes); | 96 | INIT_LIST_HEAD(&fi->queued_writes); |
96 | INIT_LIST_HEAD(&fi->writepages); | 97 | INIT_LIST_HEAD(&fi->writepages); |
@@ -139,6 +140,18 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) | |||
139 | return 0; | 140 | return 0; |
140 | } | 141 | } |
141 | 142 | ||
143 | /* | ||
144 | * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down | ||
145 | * so that it will fit. | ||
146 | */ | ||
147 | static ino_t fuse_squash_ino(u64 ino64) | ||
148 | { | ||
149 | ino_t ino = (ino_t) ino64; | ||
150 | if (sizeof(ino_t) < sizeof(u64)) | ||
151 | ino ^= ino64 >> (sizeof(u64) - sizeof(ino_t)) * 8; | ||
152 | return ino; | ||
153 | } | ||
154 | |||
142 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | 155 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, |
143 | u64 attr_valid) | 156 | u64 attr_valid) |
144 | { | 157 | { |
@@ -148,7 +161,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |||
148 | fi->attr_version = ++fc->attr_version; | 161 | fi->attr_version = ++fc->attr_version; |
149 | fi->i_time = attr_valid; | 162 | fi->i_time = attr_valid; |
150 | 163 | ||
151 | inode->i_ino = attr->ino; | 164 | inode->i_ino = fuse_squash_ino(attr->ino); |
152 | inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); | 165 | inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); |
153 | set_nlink(inode, attr->nlink); | 166 | set_nlink(inode, attr->nlink); |
154 | inode->i_uid = attr->uid; | 167 | inode->i_uid = attr->uid; |
@@ -174,6 +187,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |||
174 | fi->orig_i_mode = inode->i_mode; | 187 | fi->orig_i_mode = inode->i_mode; |
175 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) | 188 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) |
176 | inode->i_mode &= ~S_ISVTX; | 189 | inode->i_mode &= ~S_ISVTX; |
190 | |||
191 | fi->orig_ino = attr->ino; | ||
177 | } | 192 | } |
178 | 193 | ||
179 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | 194 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, |