summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/f2fs/data.c11
-rw-r--r--fs/f2fs/f2fs.h1
-rw-r--r--fs/f2fs/super.c2
-rw-r--r--fs/fuse/dev.c5
-rw-r--r--fs/fuse/dir.c45
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/notify/inotify/inotify_user.c2
-rwxr-xr-xfs/sdcardfs/dentry.c6
-rw-r--r--include/linux/dcache.h2
-rw-r--r--include/uapi/linux/fuse.h1
10 files changed, 73 insertions, 5 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 5e50ab4fab9c..f7aae7459bc5 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -730,6 +730,15 @@ static int get_data_block(struct inode *inode, sector_t iblock,
return __get_data_block(inode, iblock, bh_result, create, false);
}
+static int get_data_block_bmap(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create)
+{
+ /* Block number less than F2FS MAX BLOCKS */
+ if (unlikely(iblock >= max_file_size(0)))
+ return -EFBIG;
+ return __get_data_block(inode, iblock, bh_result, create, false);
+}
+
static int get_data_block_fiemap(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
@@ -1163,7 +1172,7 @@ static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
if (f2fs_has_inline_data(inode))
return 0;
- return generic_block_bmap(mapping, block, get_data_block);
+ return generic_block_bmap(mapping, block, get_data_block_bmap);
}
const struct address_space_operations f2fs_dblock_aops = {
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 499758458ccf..20feb206e4a7 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1305,6 +1305,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
/*
* super.c
*/
+loff_t max_file_size(unsigned bits);
int f2fs_sync_fs(struct super_block *, int);
extern __printf(3, 4)
void f2fs_msg(struct super_block *, const char *, const char *, ...);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index ab5e516684c9..176b2f424274 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -836,7 +836,7 @@ static const struct export_operations f2fs_export_ops = {
.get_parent = f2fs_get_parent,
};
-static loff_t max_file_size(unsigned bits)
+loff_t max_file_size(unsigned bits)
{
loff_t result = (DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS);
loff_t leaf_count = ADDRS_PER_BLOCK;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index f4e875a29e7a..69eee305d36e 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -13,6 +13,7 @@
#include <linux/poll.h>
#include <linux/uio.h>
#include <linux/miscdevice.h>
+#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/file.h>
#include <linux/slab.h>
@@ -1874,6 +1875,10 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc,
spin_unlock(&fc->lock);
err = copy_out_args(cs, &req->out, nbytes);
+ if (req->in.h.opcode == FUSE_CANONICAL_PATH) {
+ req->out.h.error = kern_path((char *)req->out.args[0].value, 0,
+ req->canonical_path);
+ }
fuse_copy_finish(cs);
spin_lock(&fc->lock);
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index e67b13de2ebc..7668bbcd444a 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -252,6 +252,50 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
return 1;
}
+/*
+ * Get the canonical path. Since we must translate to a path, this must be done
+ * in the context of the userspace daemon, however, the userspace daemon cannot
+ * look up paths on its own. Instead, we handle the lookup as a special case
+ * inside of the write request.
+ */
+static void fuse_dentry_canonical_path(const struct path *path, struct path *canonical_path) {
+ struct inode *inode = path->dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_req *req;
+ int err;
+ char *path_name;
+
+ req = fuse_get_req(fc, 1);
+ err = PTR_ERR(req);
+ if (IS_ERR(req))
+ goto default_path;
+
+ path_name = (char*)__get_free_page(GFP_KERNEL);
+ if (!path_name) {
+ fuse_put_request(fc, req);
+ goto default_path;
+ }
+
+ req->in.h.opcode = FUSE_CANONICAL_PATH;
+ req->in.h.nodeid = get_node_id(inode);
+ req->in.numargs = 0;
+ req->out.numargs = 1;
+ req->out.args[0].size = PATH_MAX;
+ req->out.args[0].value = path_name;
+ req->canonical_path = canonical_path;
+ req->out.argvar = 1;
+ fuse_request_send(fc, req);
+ err = req->out.h.error;
+ fuse_put_request(fc, req);
+ free_page((unsigned long)path_name);
+ if (!err)
+ return;
+default_path:
+ canonical_path->dentry = path->dentry;
+ canonical_path->mnt = path->mnt;
+ path_get(canonical_path);
+}
+
static int invalid_nodeid(u64 nodeid)
{
return !nodeid || nodeid == FUSE_ROOT_ID;
@@ -259,6 +303,7 @@ static int invalid_nodeid(u64 nodeid)
const struct dentry_operations fuse_dentry_operations = {
.d_revalidate = fuse_dentry_revalidate,
+ .d_canonical_path = fuse_dentry_canonical_path,
};
int fuse_valid_type(int m)
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 5ced199b50bb..93f861a6d36d 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -348,6 +348,9 @@ struct fuse_req {
/** Inode used in the request or NULL */
struct inode *inode;
+ /** Path used for completing d_canonical_path */
+ struct path *canonical_path;
+
/** AIO control block */
struct fuse_io_priv *io;
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index a9d3e30f06c5..fce2b8502237 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -770,7 +770,7 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
/* support stacked filesystems */
if(path.dentry && path.dentry->d_op) {
if (path.dentry->d_op->d_canonical_path) {
- path.dentry->d_op->d_canonical_path(path.dentry, &alteredpath);
+ path.dentry->d_op->d_canonical_path(&path, &alteredpath);
canonical_path = &alteredpath;
path_put(&path);
}
diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c
index 6497fb7199f3..b2fa36f13e73 100755
--- a/fs/sdcardfs/dentry.c
+++ b/fs/sdcardfs/dentry.c
@@ -173,11 +173,15 @@ static int sdcardfs_cmp_ci(const struct dentry *parent,
return 1;
}
+static void sdcardfs_canonical_path(const struct path *path, struct path *actual_path) {
+ sdcardfs_get_real_lower(path->dentry, actual_path);
+}
+
const struct dentry_operations sdcardfs_ci_dops = {
.d_revalidate = sdcardfs_d_revalidate,
.d_release = sdcardfs_d_release,
.d_hash = sdcardfs_hash_ci,
.d_compare = sdcardfs_cmp_ci,
- .d_canonical_path = sdcardfs_get_real_lower,
+ .d_canonical_path = sdcardfs_canonical_path,
};
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 00eaec48cd44..7bd16b926d5f 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -158,7 +158,7 @@ struct dentry_operations {
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
int (*d_manage)(struct dentry *, bool);
- void (*d_canonical_path)(const struct dentry *, struct path *);
+ void (*d_canonical_path)(const struct path *, struct path *);
} ____cacheline_aligned;
/*
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 60bb2f9f7b74..c5902767c595 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -343,6 +343,7 @@ enum fuse_opcode {
FUSE_BATCH_FORGET = 42,
FUSE_FALLOCATE = 43,
FUSE_READDIRPLUS = 44,
+ FUSE_CANONICAL_PATH= 2016,
/* CUSE specific operations */
CUSE_INIT = 4096,