From f2ee3b759593c184f1249e03d613a84b4b69db2b Mon Sep 17 00:00:00 2001 From: Martin Brandenburg Date: Tue, 9 Aug 2016 15:59:26 -0400 Subject: [PATCH 1/4] orangefs: record userspace version for feature compatbility The client reports its version to the kernel on startup. We already test that it is above the minimum version. Now we record it in a global variable so code elsewhere can consult it before making a request the client may not understand. Signed-off-by: Martin Brandenburg --- fs/orangefs/devorangefs-req.c | 10 ++++++++++ fs/orangefs/orangefs-kernel.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c index a287a66d94e35..7c40e653e526c 100644 --- a/fs/orangefs/devorangefs-req.c +++ b/fs/orangefs/devorangefs-req.c @@ -17,6 +17,8 @@ /* this file implements the /dev/pvfs2-req device node */ +uint32_t userspace_version; + static int open_access_count; #define DUMP_DEVICE_ERROR() \ @@ -387,6 +389,13 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, return -EPROTO; } + if (!userspace_version) { + userspace_version = head.version; + } else if (userspace_version != head.version) { + gossip_err("Error: userspace version changes\n"); + return -EPROTO; + } + /* remove the op from the in progress hash table */ op = orangefs_devreq_remove_op(head.tag); if (!op) { @@ -527,6 +536,7 @@ static int orangefs_devreq_release(struct inode *inode, struct file *file) gossip_debug(GOSSIP_DEV_DEBUG, "pvfs2-client-core: device close complete\n"); open_access_count = 0; + userspace_version = 0; mutex_unlock(&devreq_mutex); return 0; } diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h index 633c07a6e3d80..ff3566a8388f4 100644 --- a/fs/orangefs/orangefs-kernel.h +++ b/fs/orangefs/orangefs-kernel.h @@ -506,6 +506,8 @@ ssize_t orangefs_inode_read(struct inode *inode, /* * defined in devorangefs-req.c */ +extern uint32_t userspace_version; + int orangefs_dev_init(void); void orangefs_dev_cleanup(void); int is_daemon_in_service(void); From 482664ddba81b3a5404fd083bb9697dfffc0b6a4 Mon Sep 17 00:00:00 2001 From: Martin Brandenburg Date: Fri, 12 Aug 2016 12:02:31 -0400 Subject: [PATCH 2/4] orangefs: add features op This is a new userspace operation, which will be done if the client-core version is greater than or equal to 2.9.6. This will provide a way to implement optional features and to determine which features are supported by the client-core. If the client-core version is older than 2.9.6, no optional features are supported and the op will not be done. The intent is to allow protocol extensions without relying on the client-core's current behavior of ignoring what it doesn't understand. Signed-off-by: Martin Brandenburg --- fs/orangefs/devorangefs-req.c | 10 +++++----- fs/orangefs/downcall.h | 6 ++++++ fs/orangefs/orangefs-cache.c | 2 ++ fs/orangefs/orangefs-dev-proto.h | 4 ++++ fs/orangefs/orangefs-kernel.h | 4 +++- fs/orangefs/super.c | 27 +++++++++++++++++++++++++++ fs/orangefs/upcall.h | 6 ++++++ 7 files changed, 53 insertions(+), 6 deletions(-) diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c index 7c40e653e526c..ec1a5ff1d8430 100644 --- a/fs/orangefs/devorangefs-req.c +++ b/fs/orangefs/devorangefs-req.c @@ -17,7 +17,7 @@ /* this file implements the /dev/pvfs2-req device node */ -uint32_t userspace_version; +uint32_t orangefs_userspace_version; static int open_access_count; @@ -389,9 +389,9 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, return -EPROTO; } - if (!userspace_version) { - userspace_version = head.version; - } else if (userspace_version != head.version) { + if (!orangefs_userspace_version) { + orangefs_userspace_version = head.version; + } else if (orangefs_userspace_version != head.version) { gossip_err("Error: userspace version changes\n"); return -EPROTO; } @@ -536,7 +536,7 @@ static int orangefs_devreq_release(struct inode *inode, struct file *file) gossip_debug(GOSSIP_DEV_DEBUG, "pvfs2-client-core: device close complete\n"); open_access_count = 0; - userspace_version = 0; + orangefs_userspace_version = 0; mutex_unlock(&devreq_mutex); return 0; } diff --git a/fs/orangefs/downcall.h b/fs/orangefs/downcall.h index db6e8722a89e6..3b8923f8bf21d 100644 --- a/fs/orangefs/downcall.h +++ b/fs/orangefs/downcall.h @@ -101,6 +101,11 @@ struct orangefs_fs_key_response { char fs_key[FS_KEY_BUF_SIZE]; }; +/* 2.9.6 */ +struct orangefs_features_response { + __u64 features; +}; + struct orangefs_downcall_s { __s32 type; __s32 status; @@ -122,6 +127,7 @@ struct orangefs_downcall_s { struct orangefs_param_response param; struct orangefs_perf_count_response perf_count; struct orangefs_fs_key_response fs_key; + struct orangefs_features_response features; } resp; }; diff --git a/fs/orangefs/orangefs-cache.c b/fs/orangefs/orangefs-cache.c index eb0b6e00b519d..aa3830b741c78 100644 --- a/fs/orangefs/orangefs-cache.c +++ b/fs/orangefs/orangefs-cache.c @@ -97,6 +97,8 @@ char *get_opname_string(struct orangefs_kernel_op_s *new_op) return "OP_FSYNC"; else if (type == ORANGEFS_VFS_OP_FSKEY) return "OP_FSKEY"; + else if (type == ORANGEFS_VFS_OP_FEATURES) + return "OP_FEATURES"; } return "OP_UNKNOWN?"; } diff --git a/fs/orangefs/orangefs-dev-proto.h b/fs/orangefs/orangefs-dev-proto.h index 71902899b1daf..a3d84ffee9050 100644 --- a/fs/orangefs/orangefs-dev-proto.h +++ b/fs/orangefs/orangefs-dev-proto.h @@ -41,6 +41,10 @@ #define ORANGEFS_VFS_OP_FSYNC 0xFF00EE01 #define ORANGEFS_VFS_OP_FSKEY 0xFF00EE02 #define ORANGEFS_VFS_OP_READDIRPLUS 0xFF00EE03 +#define ORANGEFS_VFS_OP_FEATURES 0xFF00EE05 /* 2.9.6 */ + +/* features is a 64-bit unsigned bitmask */ +#define ORANGEFS_FEATURE_READAHEAD 1 /* * Misc constants. Please retain them as multiples of 8! diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h index ff3566a8388f4..6cf3f467fd893 100644 --- a/fs/orangefs/orangefs-kernel.h +++ b/fs/orangefs/orangefs-kernel.h @@ -447,6 +447,8 @@ void purge_waiting_ops(void); /* * defined in super.c */ +extern uint64_t orangefs_features; + struct dentry *orangefs_mount(struct file_system_type *fst, int flags, const char *devname, @@ -506,7 +508,7 @@ ssize_t orangefs_inode_read(struct inode *inode, /* * defined in devorangefs-req.c */ -extern uint32_t userspace_version; +extern uint32_t orangefs_userspace_version; int orangefs_dev_init(void); void orangefs_dev_cleanup(void); diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c index b9da9a0281c9b..3e484a6673409 100644 --- a/fs/orangefs/super.c +++ b/fs/orangefs/super.c @@ -33,6 +33,7 @@ static const match_table_t tokens = { { Opt_err, NULL } }; +uint64_t orangefs_features; static int parse_mount_options(struct super_block *sb, char *options, int silent) @@ -249,6 +250,19 @@ int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb) } op_release(new_op); + + if (orangefs_userspace_version >= 20906) { + new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES); + if (!new_op) + return -ENOMEM; + new_op->upcall.req.features.features = 0; + ret = service_operation(new_op, "orangefs_features", 0); + orangefs_features = new_op->downcall.resp.features.features; + op_release(new_op); + } else { + orangefs_features = 0; + } + return ret; } @@ -492,6 +506,19 @@ struct dentry *orangefs_mount(struct file_system_type *fst, list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks); spin_unlock(&orangefs_superblocks_lock); op_release(new_op); + + if (orangefs_userspace_version >= 20906) { + new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES); + if (!new_op) + return ERR_PTR(-ENOMEM); + new_op->upcall.req.features.features = 0; + ret = service_operation(new_op, "orangefs_features", 0); + orangefs_features = new_op->downcall.resp.features.features; + op_release(new_op); + } else { + orangefs_features = 0; + } + return dget(sb->s_root); free_op: diff --git a/fs/orangefs/upcall.h b/fs/orangefs/upcall.h index 7c29fdf08ec51..af0b0e36d5595 100644 --- a/fs/orangefs/upcall.h +++ b/fs/orangefs/upcall.h @@ -210,6 +210,11 @@ struct orangefs_fs_key_request_s { __s32 __pad1; }; +/* 2.9.6 */ +struct orangefs_features_request_s { + __u64 features; +}; + struct orangefs_upcall_s { __s32 type; __u32 uid; @@ -246,6 +251,7 @@ struct orangefs_upcall_s { struct orangefs_param_request_s param; struct orangefs_perf_count_request_s perf_count; struct orangefs_fs_key_request_s fs_key; + struct orangefs_features_request_s features; } req; }; From c51e012942a7594f59db5611db14fa4a29624a10 Mon Sep 17 00:00:00 2001 From: Martin Brandenburg Date: Fri, 12 Aug 2016 16:12:09 -0400 Subject: [PATCH 3/4] orangefs: do not allow client readahead cache without feature bit Signed-off-by: Martin Brandenburg --- fs/orangefs/file.c | 13 ++++++++----- fs/orangefs/orangefs-sysfs.c | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index 43c08b5c71686..fe5e1eac95619 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -624,11 +624,14 @@ static int orangefs_file_release(struct inode *inode, struct file *file) if (file->f_path.dentry->d_inode && file->f_path.dentry->d_inode->i_mapping && mapping_nrpages(&file->f_path.dentry->d_inode->i_data)) { - gossip_debug(GOSSIP_INODE_DEBUG, - "calling flush_racache on %pU\n", - get_khandle_from_ino(inode)); - flush_racache(inode); - gossip_debug(GOSSIP_INODE_DEBUG, "flush_racache finished\n"); + if (orangefs_features & ORANGEFS_FEATURE_READAHEAD) { + gossip_debug(GOSSIP_INODE_DEBUG, + "calling flush_racache on %pU\n", + get_khandle_from_ino(inode)); + flush_racache(inode); + gossip_debug(GOSSIP_INODE_DEBUG, + "flush_racache finished\n"); + } truncate_inode_pages(file->f_path.dentry->d_inode->i_mapping, 0); } diff --git a/fs/orangefs/orangefs-sysfs.c b/fs/orangefs/orangefs-sysfs.c index 2fe9a3a2117bd..ed5ee33d0f7ea 100644 --- a/fs/orangefs/orangefs-sysfs.c +++ b/fs/orangefs/orangefs-sysfs.c @@ -842,6 +842,16 @@ static int sysfs_service_op_show(char *kobj_id, char *buf, void *attr) if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) { orangefs_attr = (struct orangefs_attribute *)attr; + /* Drop unsupported requests first. */ + if (!(orangefs_features & ORANGEFS_FEATURE_READAHEAD) && + (!strcmp(orangefs_attr->attr.name, "readahead_count") || + !strcmp(orangefs_attr->attr.name, "readahead_size") || + !strcmp(orangefs_attr->attr.name, + "readahead_count_size"))) { + rc = -EINVAL; + goto out; + } + if (!strcmp(orangefs_attr->attr.name, "perf_history_size")) new_op->upcall.req.param.op = ORANGEFS_PARAM_REQUEST_OP_PERF_HISTORY_SIZE; @@ -1133,6 +1143,15 @@ static int sysfs_service_op_store(char *kobj_id, const char *buf, void *attr) if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) { orangefs_attr = (struct orangefs_attribute *)attr; + /* Drop unsupported requests first. */ + if (!(orangefs_features & ORANGEFS_FEATURE_READAHEAD) && + (!strcmp(orangefs_attr->attr.name, "readahead_count") || + !strcmp(orangefs_attr->attr.name, "readahead_size") || + !strcmp(orangefs_attr->attr.name, + "readahead_count_size"))) { + rc = -EINVAL; + goto out; + } if (!strcmp(orangefs_attr->attr.name, "perf_history_size")) { if (val > 0) { From 0c95ad76361f1d75a1ffdf82deafbcec44d19c42 Mon Sep 17 00:00:00 2001 From: Martin Brandenburg Date: Wed, 21 Sep 2016 12:37:23 -0400 Subject: [PATCH 4/4] orangefs: bump minimum userspace version OrangeFS 2.9.6 was released without support for the features op. Thus OrangeFS 2.9.7 will be required to use it. Signed-off-by: Martin Brandenburg --- fs/orangefs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c index 3e484a6673409..b4ab1c1e82784 100644 --- a/fs/orangefs/super.c +++ b/fs/orangefs/super.c @@ -251,7 +251,7 @@ int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb) op_release(new_op); - if (orangefs_userspace_version >= 20906) { + if (orangefs_userspace_version >= 20907) { new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES); if (!new_op) return -ENOMEM; @@ -507,7 +507,7 @@ struct dentry *orangefs_mount(struct file_system_type *fst, spin_unlock(&orangefs_superblocks_lock); op_release(new_op); - if (orangefs_userspace_version >= 20906) { + if (orangefs_userspace_version >= 20907) { new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES); if (!new_op) return ERR_PTR(-ENOMEM);