diff options
author | Tom Van Braeckel <tomvanbraeckel@gmail.com> | 2015-01-11 23:22:16 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2015-03-19 10:29:22 -0400 |
commit | 94e4fe2cab3d43b3ba7c3f721743006a8c9d913a (patch) | |
tree | b6bb327977ae0e4a1173ab32bb4f93f9b460e17e | |
parent | aa991b3b267e24f578bac7b09cc57579b660304b (diff) |
fuse: explicitly set /dev/fuse file's private_data
The misc subsystem (which is used for /dev/fuse) initializes private_data to
point to the misc device when a driver has registered a custom open file
operation, and initializes it to NULL when a custom open file operation has
*not* been provided.
This subtle quirk is confusing, to the point where kernel code registers
*empty* file open operations to have private_data point to the misc device
structure. And it leads to bugs, where the addition or removal of a custom open
file operation surprisingly changes the initial contents of a file's
private_data structure.
So to simplify things in the misc subsystem, a patch [1] has been proposed to
*always* set the private_data to point to the misc device, instead of only
doing this when a custom open file operation has been registered.
But before this patch can be applied we need to modify drivers that make the
assumption that a misc device file's private_data is initialized to NULL
because they didn't register a custom open file operation, so they don't rely
on this assumption anymore. FUSE uses private_data to store the fuse_conn and
errors out if this is not initialized to NULL at mount time.
Hence, we now set a file's private_data to NULL explicitly, to be independent
of whatever value the misc subsystem initializes it to by default.
[1] https://lkml.org/lkml/2014/12/4/939
Reported-by: Giedrius Statkevicius <giedriuswork@gmail.com>
Reported-by: Thierry Reding <thierry.reding@gmail.com>
Signed-off-by: Tom Van Braeckel <tomvanbraeckel@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
-rw-r--r-- | fs/fuse/dev.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 71c4619af333..39706c57ad3c 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -1353,6 +1353,17 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file, | |||
1353 | return err; | 1353 | return err; |
1354 | } | 1354 | } |
1355 | 1355 | ||
1356 | static int fuse_dev_open(struct inode *inode, struct file *file) | ||
1357 | { | ||
1358 | /* | ||
1359 | * The fuse device's file's private_data is used to hold | ||
1360 | * the fuse_conn(ection) when it is mounted, and is used to | ||
1361 | * keep track of whether the file has been mounted already. | ||
1362 | */ | ||
1363 | file->private_data = NULL; | ||
1364 | return 0; | ||
1365 | } | ||
1366 | |||
1356 | static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov, | 1367 | static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov, |
1357 | unsigned long nr_segs, loff_t pos) | 1368 | unsigned long nr_segs, loff_t pos) |
1358 | { | 1369 | { |
@@ -2220,6 +2231,7 @@ static int fuse_dev_fasync(int fd, struct file *file, int on) | |||
2220 | 2231 | ||
2221 | const struct file_operations fuse_dev_operations = { | 2232 | const struct file_operations fuse_dev_operations = { |
2222 | .owner = THIS_MODULE, | 2233 | .owner = THIS_MODULE, |
2234 | .open = fuse_dev_open, | ||
2223 | .llseek = no_llseek, | 2235 | .llseek = no_llseek, |
2224 | .read = do_sync_read, | 2236 | .read = do_sync_read, |
2225 | .aio_read = fuse_dev_read, | 2237 | .aio_read = fuse_dev_read, |