Loading fs/nfs/callback.h +4 −1 Original line number Diff line number Diff line Loading @@ -106,6 +106,8 @@ struct cb_sequenceres { extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, struct cb_sequenceres *res); extern int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid); #define RCA4_TYPE_MASK_RDATA_DLG 0 #define RCA4_TYPE_MASK_WDATA_DLG 1 Loading @@ -125,8 +127,9 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); #ifdef CONFIG_NFS_V4 extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); extern void nfs_callback_down(int minorversion); extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid); #endif /* CONFIG_NFS_V4 */ /* * nfs41: Callbacks are expected to not cause substantial latency, * so we limit their concurrency to 1 by setting up the maximum number Loading fs/nfs/callback_proc.c +35 −2 Original line number Diff line number Diff line Loading @@ -61,6 +61,16 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres * return res->status; } static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *) { #if defined(CONFIG_NFS_V4_1) if (clp->cl_minorversion > 0) return nfs41_validate_delegation_stateid; #endif return nfs4_validate_delegation_stateid; } __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) { struct nfs_client *clp; Loading @@ -81,7 +91,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) inode = nfs_delegation_find_inode(clp, &args->fh); if (inode != NULL) { /* Set up a helper thread to actually return the delegation */ switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { switch (nfs_async_inode_return_delegation(inode, &args->stateid, nfs_validate_delegation_stateid(clp))) { case 0: res = 0; break; Loading @@ -102,8 +113,31 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) return res; } int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) { if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, sizeof(delegation->stateid.data)) != 0) return 0; return 1; } #if defined(CONFIG_NFS_V4_1) int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) { if (delegation == NULL) return 0; /* seqid is 4-bytes long */ if (((u32 *) &stateid->data)[0] != 0) return 0; if (memcmp(&delegation->stateid.data[4], &stateid->data[4], sizeof(stateid->data)-4)) return 0; return 1; } /* * Validate the sequenceID sent by the server. * Return success if the sequenceID is one more than what we last saw on Loading Loading @@ -255,5 +289,4 @@ unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy) dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; } #endif /* CONFIG_NFS_V4_1 */ fs/nfs/delegation.c +6 −3 Original line number Diff line number Diff line Loading @@ -454,18 +454,21 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp) /* * Asynchronous delegation recall! */ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, int (*validate_stateid)(struct nfs_delegation *delegation, const nfs4_stateid *stateid)) { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_delegation *delegation; rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, sizeof(delegation->stateid.data)) != 0) { if (!validate_stateid(delegation, stateid)) { rcu_read_unlock(); return -ENOENT; } nfs_mark_return_delegation(clp, delegation); rcu_read_unlock(); nfs_delegation_run_state_manager(clp); Loading fs/nfs/delegation.h +3 −1 Original line number Diff line number Diff line Loading @@ -34,7 +34,9 @@ enum { int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); int nfs_inode_return_delegation(struct inode *inode); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, int (*validate_stateid)(struct nfs_delegation *delegation, const nfs4_stateid *stateid)); void nfs_inode_return_delegation_noreclaim(struct inode *inode); struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); Loading Loading
fs/nfs/callback.h +4 −1 Original line number Diff line number Diff line Loading @@ -106,6 +106,8 @@ struct cb_sequenceres { extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, struct cb_sequenceres *res); extern int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid); #define RCA4_TYPE_MASK_RDATA_DLG 0 #define RCA4_TYPE_MASK_WDATA_DLG 1 Loading @@ -125,8 +127,9 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); #ifdef CONFIG_NFS_V4 extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); extern void nfs_callback_down(int minorversion); extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid); #endif /* CONFIG_NFS_V4 */ /* * nfs41: Callbacks are expected to not cause substantial latency, * so we limit their concurrency to 1 by setting up the maximum number Loading
fs/nfs/callback_proc.c +35 −2 Original line number Diff line number Diff line Loading @@ -61,6 +61,16 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres * return res->status; } static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *) { #if defined(CONFIG_NFS_V4_1) if (clp->cl_minorversion > 0) return nfs41_validate_delegation_stateid; #endif return nfs4_validate_delegation_stateid; } __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) { struct nfs_client *clp; Loading @@ -81,7 +91,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) inode = nfs_delegation_find_inode(clp, &args->fh); if (inode != NULL) { /* Set up a helper thread to actually return the delegation */ switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { switch (nfs_async_inode_return_delegation(inode, &args->stateid, nfs_validate_delegation_stateid(clp))) { case 0: res = 0; break; Loading @@ -102,8 +113,31 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) return res; } int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) { if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, sizeof(delegation->stateid.data)) != 0) return 0; return 1; } #if defined(CONFIG_NFS_V4_1) int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) { if (delegation == NULL) return 0; /* seqid is 4-bytes long */ if (((u32 *) &stateid->data)[0] != 0) return 0; if (memcmp(&delegation->stateid.data[4], &stateid->data[4], sizeof(stateid->data)-4)) return 0; return 1; } /* * Validate the sequenceID sent by the server. * Return success if the sequenceID is one more than what we last saw on Loading Loading @@ -255,5 +289,4 @@ unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy) dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; } #endif /* CONFIG_NFS_V4_1 */
fs/nfs/delegation.c +6 −3 Original line number Diff line number Diff line Loading @@ -454,18 +454,21 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp) /* * Asynchronous delegation recall! */ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, int (*validate_stateid)(struct nfs_delegation *delegation, const nfs4_stateid *stateid)) { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_delegation *delegation; rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, sizeof(delegation->stateid.data)) != 0) { if (!validate_stateid(delegation, stateid)) { rcu_read_unlock(); return -ENOENT; } nfs_mark_return_delegation(clp, delegation); rcu_read_unlock(); nfs_delegation_run_state_manager(clp); Loading
fs/nfs/delegation.h +3 −1 Original line number Diff line number Diff line Loading @@ -34,7 +34,9 @@ enum { int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); int nfs_inode_return_delegation(struct inode *inode); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, int (*validate_stateid)(struct nfs_delegation *delegation, const nfs4_stateid *stateid)); void nfs_inode_return_delegation_noreclaim(struct inode *inode); struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); Loading