51
51
#include <linux/sunrpc/rpc_pipe_fs.h>
52
52
#include <linux/sunrpc/gss_api.h>
53
53
#include <asm/uaccess.h>
54
+ #include <linux/hashtable.h>
54
55
55
56
#include "../netns.h"
56
57
@@ -71,6 +72,9 @@ static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
71
72
* using integrity (two 4-byte integers): */
72
73
#define GSS_VERF_SLACK 100
73
74
75
+ static DEFINE_HASHTABLE (gss_auth_hash_table , 16 ) ;
76
+ static DEFINE_SPINLOCK (gss_auth_hash_lock );
77
+
74
78
struct gss_pipe {
75
79
struct rpc_pipe_dir_object pdo ;
76
80
struct rpc_pipe * pipe ;
@@ -81,6 +85,7 @@ struct gss_pipe {
81
85
82
86
struct gss_auth {
83
87
struct kref kref ;
88
+ struct hlist_node hash ;
84
89
struct rpc_auth rpc_auth ;
85
90
struct gss_api_mech * mech ;
86
91
enum rpc_gss_svc service ;
@@ -940,8 +945,8 @@ static void gss_pipe_free(struct gss_pipe *p)
940
945
* NOTE: we have the opportunity to use different
941
946
* parameters based on the input flavor (which must be a pseudoflavor)
942
947
*/
943
- static struct rpc_auth *
944
- gss_create (struct rpc_auth_create_args * args , struct rpc_clnt * clnt )
948
+ static struct gss_auth *
949
+ gss_create_new (struct rpc_auth_create_args * args , struct rpc_clnt * clnt )
945
950
{
946
951
rpc_authflavor_t flavor = args -> pseudoflavor ;
947
952
struct gss_auth * gss_auth ;
@@ -955,6 +960,7 @@ gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
955
960
return ERR_PTR (err );
956
961
if (!(gss_auth = kmalloc (sizeof (* gss_auth ), GFP_KERNEL )))
957
962
goto out_dec ;
963
+ INIT_HLIST_NODE (& gss_auth -> hash );
958
964
gss_auth -> target_name = NULL ;
959
965
if (args -> target_name ) {
960
966
gss_auth -> target_name = kstrdup (args -> target_name , GFP_KERNEL );
@@ -1004,7 +1010,7 @@ gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
1004
1010
}
1005
1011
gss_auth -> gss_pipe [0 ] = gss_pipe ;
1006
1012
1007
- return auth ;
1013
+ return gss_auth ;
1008
1014
err_destroy_pipe_1 :
1009
1015
gss_pipe_free (gss_auth -> gss_pipe [1 ]);
1010
1016
err_destroy_credcache :
@@ -1051,6 +1057,12 @@ gss_destroy(struct rpc_auth *auth)
1051
1057
dprintk ("RPC: destroying GSS authenticator %p flavor %d\n" ,
1052
1058
auth , auth -> au_flavor );
1053
1059
1060
+ if (hash_hashed (& gss_auth -> hash )) {
1061
+ spin_lock (& gss_auth_hash_lock );
1062
+ hash_del (& gss_auth -> hash );
1063
+ spin_unlock (& gss_auth_hash_lock );
1064
+ }
1065
+
1054
1066
gss_pipe_free (gss_auth -> gss_pipe [0 ]);
1055
1067
gss_auth -> gss_pipe [0 ] = NULL ;
1056
1068
gss_pipe_free (gss_auth -> gss_pipe [1 ]);
@@ -1060,6 +1072,80 @@ gss_destroy(struct rpc_auth *auth)
1060
1072
kref_put (& gss_auth -> kref , gss_free_callback );
1061
1073
}
1062
1074
1075
+ static struct gss_auth *
1076
+ gss_auth_find_or_add_hashed (struct rpc_auth_create_args * args ,
1077
+ struct rpc_clnt * clnt ,
1078
+ struct gss_auth * new )
1079
+ {
1080
+ struct gss_auth * gss_auth ;
1081
+ unsigned long hashval = (unsigned long )clnt ;
1082
+
1083
+ spin_lock (& gss_auth_hash_lock );
1084
+ hash_for_each_possible (gss_auth_hash_table ,
1085
+ gss_auth ,
1086
+ hash ,
1087
+ hashval ) {
1088
+ if (gss_auth -> rpc_auth .au_flavor != args -> pseudoflavor )
1089
+ continue ;
1090
+ if (gss_auth -> target_name != args -> target_name ) {
1091
+ if (gss_auth -> target_name == NULL )
1092
+ continue ;
1093
+ if (args -> target_name == NULL )
1094
+ continue ;
1095
+ if (strcmp (gss_auth -> target_name , args -> target_name ))
1096
+ continue ;
1097
+ }
1098
+ if (!atomic_inc_not_zero (& gss_auth -> rpc_auth .au_count ))
1099
+ continue ;
1100
+ goto out ;
1101
+ }
1102
+ if (new )
1103
+ hash_add (gss_auth_hash_table , & new -> hash , hashval );
1104
+ gss_auth = new ;
1105
+ out :
1106
+ spin_unlock (& gss_auth_hash_lock );
1107
+ return gss_auth ;
1108
+ }
1109
+
1110
+ static struct gss_auth *
1111
+ gss_create_hashed (struct rpc_auth_create_args * args , struct rpc_clnt * clnt )
1112
+ {
1113
+ struct gss_auth * gss_auth ;
1114
+ struct gss_auth * new ;
1115
+
1116
+ gss_auth = gss_auth_find_or_add_hashed (args , clnt , NULL );
1117
+ if (gss_auth != NULL )
1118
+ goto out ;
1119
+ new = gss_create_new (args , clnt );
1120
+ if (IS_ERR (new ))
1121
+ return new ;
1122
+ gss_auth = gss_auth_find_or_add_hashed (args , clnt , new );
1123
+ if (gss_auth != new )
1124
+ gss_destroy (& new -> rpc_auth );
1125
+ out :
1126
+ return gss_auth ;
1127
+ }
1128
+
1129
+ static struct rpc_auth *
1130
+ gss_create (struct rpc_auth_create_args * args , struct rpc_clnt * clnt )
1131
+ {
1132
+ struct gss_auth * gss_auth ;
1133
+ struct rpc_xprt * xprt = rcu_access_pointer (clnt -> cl_xprt );
1134
+
1135
+ while (clnt != clnt -> cl_parent ) {
1136
+ struct rpc_clnt * parent = clnt -> cl_parent ;
1137
+ /* Find the original parent for this transport */
1138
+ if (rcu_access_pointer (parent -> cl_xprt ) != xprt )
1139
+ break ;
1140
+ clnt = parent ;
1141
+ }
1142
+
1143
+ gss_auth = gss_create_hashed (args , clnt );
1144
+ if (IS_ERR (gss_auth ))
1145
+ return ERR_CAST (gss_auth );
1146
+ return & gss_auth -> rpc_auth ;
1147
+ }
1148
+
1063
1149
/*
1064
1150
* gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call
1065
1151
* to the server with the GSS control procedure field set to
0 commit comments