Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fuse: add blksize field to fuse_attr

There are cases when the filesystem will be passed the buffer from a single
read or write call, namely:

1) in 'direct-io' mode (not O_DIRECT), read/write requests don't go
through the page cache, but go directly to the userspace fs

2) currently buffered writes are done with single page requests, but
if Nick's ->perform_write() patch goes it, it will be possible to
do larger write requests. But only if the original write() was
also bigger than a page.

In these cases the filesystem might want to give a hint to the app
about the optimal I/O size.

Allow the userspace filesystem to supply a blksize value to be returned by
stat() and friends. If the field is zero, it defaults to the old
PAGE_CACHE_SIZE value.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Miklos Szeredi and committed by
Linus Torvalds
0e9663ee f3332114

+39 -5
+27 -5
fs/fuse/dir.c
··· 116 116 struct dentry *entry, 117 117 struct fuse_entry_out *outarg) 118 118 { 119 + struct fuse_conn *fc = get_fuse_conn(dir); 120 + 121 + memset(outarg, 0, sizeof(struct fuse_entry_out)); 119 122 req->in.h.opcode = FUSE_LOOKUP; 120 123 req->in.h.nodeid = get_node_id(dir); 121 124 req->in.numargs = 1; 122 125 req->in.args[0].size = entry->d_name.len + 1; 123 126 req->in.args[0].value = entry->d_name.name; 124 127 req->out.numargs = 1; 125 - req->out.args[0].size = sizeof(struct fuse_entry_out); 128 + if (fc->minor < 9) 129 + req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 130 + else 131 + req->out.args[0].size = sizeof(struct fuse_entry_out); 126 132 req->out.args[0].value = outarg; 127 133 } 128 134 ··· 362 356 363 357 flags &= ~O_NOCTTY; 364 358 memset(&inarg, 0, sizeof(inarg)); 359 + memset(&outentry, 0, sizeof(outentry)); 365 360 inarg.flags = flags; 366 361 inarg.mode = mode; 367 362 req->in.h.opcode = FUSE_CREATE; ··· 373 366 req->in.args[1].size = entry->d_name.len + 1; 374 367 req->in.args[1].value = entry->d_name.name; 375 368 req->out.numargs = 2; 376 - req->out.args[0].size = sizeof(outentry); 369 + if (fc->minor < 9) 370 + req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 371 + else 372 + req->out.args[0].size = sizeof(outentry); 377 373 req->out.args[0].value = &outentry; 378 374 req->out.args[1].size = sizeof(outopen); 379 375 req->out.args[1].value = &outopen; ··· 441 431 return PTR_ERR(forget_req); 442 432 } 443 433 434 + memset(&outarg, 0, sizeof(outarg)); 444 435 req->in.h.nodeid = get_node_id(dir); 445 436 req->out.numargs = 1; 446 - req->out.args[0].size = sizeof(outarg); 437 + if (fc->minor < 9) 438 + req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 439 + else 440 + req->out.args[0].size = sizeof(outarg); 447 441 req->out.args[0].value = &outarg; 448 442 request_send(fc, req); 449 443 err = req->out.h.error; ··· 738 724 spin_unlock(&fc->lock); 739 725 740 726 memset(&inarg, 0, sizeof(inarg)); 727 + memset(&outarg, 0, sizeof(outarg)); 741 728 /* Directories have separate file-handle space */ 742 729 if (file && S_ISREG(inode->i_mode)) { 743 730 struct fuse_file *ff = file->private_data; ··· 752 737 req->in.args[0].size = sizeof(inarg); 753 738 req->in.args[0].value = &inarg; 754 739 req->out.numargs = 1; 755 - req->out.args[0].size = sizeof(outarg); 740 + if (fc->minor < 9) 741 + req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; 742 + else 743 + req->out.args[0].size = sizeof(outarg); 756 744 req->out.args[0].value = &outarg; 757 745 request_send(fc, req); 758 746 err = req->out.h.error; ··· 1120 1102 return PTR_ERR(req); 1121 1103 1122 1104 memset(&inarg, 0, sizeof(inarg)); 1105 + memset(&outarg, 0, sizeof(outarg)); 1123 1106 iattr_to_fattr(attr, &inarg); 1124 1107 if (file) { 1125 1108 struct fuse_file *ff = file->private_data; ··· 1138 1119 req->in.args[0].size = sizeof(inarg); 1139 1120 req->in.args[0].value = &inarg; 1140 1121 req->out.numargs = 1; 1141 - req->out.args[0].size = sizeof(outarg); 1122 + if (fc->minor < 9) 1123 + req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; 1124 + else 1125 + req->out.args[0].size = sizeof(outarg); 1142 1126 req->out.args[0].value = &outarg; 1143 1127 request_send(fc, req); 1144 1128 err = req->out.h.error;
+5
fs/fuse/inode.c
··· 148 148 inode->i_ctime.tv_sec = attr->ctime; 149 149 inode->i_ctime.tv_nsec = attr->ctimensec; 150 150 151 + if (attr->blksize != 0) 152 + inode->i_blkbits = ilog2(attr->blksize); 153 + else 154 + inode->i_blkbits = inode->i_sb->s_blocksize_bits; 155 + 151 156 /* 152 157 * Don't set the sticky bit in i_mode, unless we want the VFS 153 158 * to check permissions. This prevents failures due to the
+7
include/linux/fuse.h
··· 15 15 * - new fuse_getattr_in input argument of GETATTR 16 16 * - add lk_flags in fuse_lk_in 17 17 * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in 18 + * - add blksize field to fuse_attr 18 19 */ 19 20 20 21 #include <asm/types.h> ··· 54 53 __u32 uid; 55 54 __u32 gid; 56 55 __u32 rdev; 56 + __u32 blksize; 57 + __u32 padding; 57 58 }; 58 59 59 60 struct fuse_kstatfs { ··· 180 177 /* The read buffer is required to be at least 8k, but may be much larger */ 181 178 #define FUSE_MIN_READ_BUFFER 8192 182 179 180 + #define FUSE_COMPAT_ENTRY_OUT_SIZE 120 181 + 183 182 struct fuse_entry_out { 184 183 __u64 nodeid; /* Inode ID */ 185 184 __u64 generation; /* Inode generation: nodeid:gen must ··· 202 197 __u32 dummy; 203 198 __u64 fh; 204 199 }; 200 + 201 + #define FUSE_COMPAT_ATTR_OUT_SIZE 96 205 202 206 203 struct fuse_attr_out { 207 204 __u64 attr_valid; /* Cache timeout for the attributes */