aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
blob: 5c02501d0560e7ea45b86cfba3069dd1a56becb7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
 * GPL HEADER START
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 only,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License version 2 for more details (a copy is included
 * in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU General Public License
 * version 2 along with this program; If not, see
 * http://www.gnu.org/licenses/gpl-2.0.html
 *
 * GPL HEADER END
 */
/*
 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
 * Use is subject to license terms.
 *
 * Copyright (c) 2011, 2015, Intel Corporation.
 */
/*
 * This file is part of Lustre, http://www.lustre.org/
 * Lustre is a trademark of Sun Microsystems, Inc.
 */

#define MAX_STRING_SIZE 128

extern int ldlm_srv_namespace_nr;
extern int ldlm_cli_namespace_nr;
extern struct mutex ldlm_srv_namespace_lock;
extern struct list_head ldlm_srv_namespace_list;
extern struct mutex ldlm_cli_namespace_lock;
extern struct list_head ldlm_cli_active_namespace_list;

static inline int ldlm_namespace_nr_read(enum ldlm_side client)
{
	return client == LDLM_NAMESPACE_SERVER ?
		ldlm_srv_namespace_nr : ldlm_cli_namespace_nr;
}

static inline void ldlm_namespace_nr_inc(enum ldlm_side client)
{
	if (client == LDLM_NAMESPACE_SERVER)
		ldlm_srv_namespace_nr++;
	else
		ldlm_cli_namespace_nr++;
}

static inline void ldlm_namespace_nr_dec(enum ldlm_side client)
{
	if (client == LDLM_NAMESPACE_SERVER)
		ldlm_srv_namespace_nr--;
	else
		ldlm_cli_namespace_nr--;
}

static inline struct list_head *ldlm_namespace_list(enum ldlm_side client)
{
	return client == LDLM_NAMESPACE_SERVER ?
		&ldlm_srv_namespace_list : &ldlm_cli_active_namespace_list;
}

static inline struct mutex *ldlm_namespace_lock(enum ldlm_side client)
{
	return client == LDLM_NAMESPACE_SERVER ?
		&ldlm_srv_namespace_lock : &ldlm_cli_namespace_lock;
}

/* ns_bref is the number of resources in this namespace */
static inline int ldlm_ns_empty(struct ldlm_namespace *ns)
{
	return atomic_read(&ns->ns_bref) == 0;
}

void ldlm_namespace_move_to_active_locked(struct ldlm_namespace *,
					  enum ldlm_side);
void ldlm_namespace_move_to_inactive_locked(struct ldlm_namespace *,
					    enum ldlm_side);
struct ldlm_namespace *ldlm_namespace_first_locked(enum ldlm_side);

/* ldlm_request.c */
/* Cancel lru flag, it indicates we cancel aged locks. */
enum {
	LDLM_LRU_FLAG_AGED	= BIT(0), /* Cancel aged locks (non lru resize). */
	LDLM_LRU_FLAG_PASSED	= BIT(1), /* Cancel passed number of locks. */
	LDLM_LRU_FLAG_SHRINK	= BIT(2), /* Cancel locks from shrinker. */
	LDLM_LRU_FLAG_LRUR	= BIT(3), /* Cancel locks from lru resize. */
	LDLM_LRU_FLAG_NO_WAIT	= BIT(4), /* Cancel locks w/o blocking (neither
					   * sending nor waiting for any rpcs)
					   */
	LDLM_LRU_FLAG_LRUR_NO_WAIT = BIT(5), /* LRUR + NO_WAIT */
};

int ldlm_cancel_lru(struct ldlm_namespace *ns, int nr,
		    enum ldlm_cancel_flags sync, int flags);
int ldlm_cancel_lru_local(struct ldlm_namespace *ns,
			  struct list_head *cancels, int count, int max,
			  enum ldlm_cancel_flags cancel_flags, int flags);
extern unsigned int ldlm_enqueue_min;
extern unsigned int ldlm_cancel_unused_locks_before_replay;

/* ldlm_resource.c */
int ldlm_resource_putref_locked(struct ldlm_resource *res);
void ldlm_namespace_free_prior(struct ldlm_namespace *ns,
			       struct obd_import *imp, int force);
void ldlm_namespace_free_post(struct ldlm_namespace *ns);
/* ldlm_lock.c */

struct ldlm_cb_set_arg {
	struct ptlrpc_request_set	*set;
	int				 type; /* LDLM_{CP,BL,GL}_CALLBACK */
	atomic_t			 restart;
	struct list_head			*list;
	union ldlm_gl_desc		*gl_desc; /* glimpse AST descriptor */
};

enum ldlm_desc_ast_t {
	LDLM_WORK_BL_AST,
	LDLM_WORK_CP_AST,
	LDLM_WORK_REVOKE_AST,
	LDLM_WORK_GL_AST
};

void ldlm_grant_lock(struct ldlm_lock *lock, struct list_head *work_list);
int ldlm_fill_lvb(struct ldlm_lock *lock, struct req_capsule *pill,
		  enum req_location loc, void *data, int size);
struct ldlm_lock *
ldlm_lock_create(struct ldlm_namespace *ns, const struct ldlm_res_id *,
		 enum ldlm_type type, enum ldlm_mode mode,
		 const struct ldlm_callback_suite *cbs,
		 void *data, __u32 lvb_len, enum lvb_type lvb_type);
enum ldlm_error ldlm_lock_enqueue(struct ldlm_namespace *, struct ldlm_lock **,
				  void *cookie, __u64 *flags);
void ldlm_lock_addref_internal(struct ldlm_lock *, enum ldlm_mode mode);
void ldlm_lock_addref_internal_nolock(struct ldlm_lock *, enum ldlm_mode mode);
void ldlm_lock_decref_internal(struct ldlm_lock *, enum ldlm_mode mode);
void ldlm_lock_decref_internal_nolock(struct ldlm_lock *, enum ldlm_mode mode);
int ldlm_run_ast_work(struct ldlm_namespace *ns, struct list_head *rpc_list,
		      enum ldlm_desc_ast_t ast_type);
int ldlm_lock_remove_from_lru_check(struct ldlm_lock *lock, time_t last_use);
#define ldlm_lock_remove_from_lru(lock) ldlm_lock_remove_from_lru_check(lock, 0)
int ldlm_lock_remove_from_lru_nolock(struct ldlm_lock *lock);
void ldlm_lock_destroy_nolock(struct ldlm_lock *lock);

/* ldlm_lockd.c */
int ldlm_bl_to_thread_lock(struct ldlm_namespace *ns, struct ldlm_lock_desc *ld,
			   struct ldlm_lock *lock);
int ldlm_bl_to_thread_list(struct ldlm_namespace *ns,
			   struct ldlm_lock_desc *ld,
			   struct list_head *cancels, int count,
			   enum ldlm_cancel_flags cancel_flags);

void ldlm_handle_bl_callback(struct ldlm_namespace *ns,
			     struct ldlm_lock_desc *ld, struct ldlm_lock *lock);

extern struct kmem_cache *ldlm_resource_slab;
extern struct kset *ldlm_ns_kset;

/* ldlm_lockd.c & ldlm_lock.c */
extern struct kmem_cache *ldlm_lock_slab;

/* ldlm_extent.c */
void ldlm_extent_add_lock(struct ldlm_resource *res, struct ldlm_lock *lock);
void ldlm_extent_unlink_lock(struct ldlm_lock *lock);

/* l_lock.c */
void l_check_ns_lock(struct ldlm_namespace *ns);
void l_check_no_ns_lock(struct ldlm_namespace *ns);

extern struct dentry *ldlm_svc_debugfs_dir;

struct ldlm_state {
	struct ptlrpc_service *ldlm_cb_service;
	struct ptlrpc_service *ldlm_cancel_service;
	struct ptlrpc_client *ldlm_client;
	struct ptlrpc_connection *ldlm_server_conn;
	struct ldlm_bl_pool *ldlm_bl_pool;
};

/* ldlm_pool.c */
__u64 ldlm_pool_get_slv(struct ldlm_pool *pl);
void ldlm_pool_set_clv(struct ldlm_pool *pl, __u64 clv);
__u32 ldlm_pool_get_lvf(struct ldlm_pool *pl);

/* interval tree, for LDLM_EXTENT. */
extern struct kmem_cache *ldlm_interval_slab; /* slab cache for ldlm_interval */
struct ldlm_interval *ldlm_interval_detach(struct ldlm_lock *l);
struct ldlm_interval *ldlm_interval_alloc(struct ldlm_lock *lock);
void ldlm_interval_free(struct ldlm_interval *node);
/* this function must be called with res lock held */
static inline struct ldlm_extent *
ldlm_interval_extent(struct ldlm_interval *node)
{
	struct ldlm_lock *lock;

	LASSERT(!list_empty(&node->li_group));

	lock = list_entry(node->li_group.next, struct ldlm_lock, l_sl_policy);
	return &lock->l_policy_data.l_extent;
}

int ldlm_init(void);
void ldlm_exit(void);

enum ldlm_policy_res {
	LDLM_POLICY_CANCEL_LOCK,
	LDLM_POLICY_KEEP_LOCK,
	LDLM_POLICY_SKIP_LOCK
};

#define LDLM_POOL_SYSFS_PRINT_int(v) sprintf(buf, "%d\n", v)
#define LDLM_POOL_SYSFS_SET_int(a, b) { a = b; }
#define LDLM_POOL_SYSFS_PRINT_u64(v) sprintf(buf, "%lld\n", v)
#define LDLM_POOL_SYSFS_SET_u64(a, b) { a = b; }
#define LDLM_POOL_SYSFS_PRINT_atomic(v) sprintf(buf, "%d\n", atomic_read(&v))
#define LDLM_POOL_SYSFS_SET_atomic(a, b) atomic_set(&a, b)

#define LDLM_POOL_SYSFS_READER_SHOW(var, type)				    \
	static ssize_t var##_show(struct kobject *kobj,			    \
				  struct attribute *attr,		    \
				  char *buf)				    \
	{								    \
		struct ldlm_pool *pl = container_of(kobj, struct ldlm_pool, \
						    pl_kobj);		    \
		type tmp;						    \
									    \
		spin_lock(&pl->pl_lock);				    \
		tmp = pl->pl_##var;					    \
		spin_unlock(&pl->pl_lock);				    \
									    \
		return LDLM_POOL_SYSFS_PRINT_##type(tmp);		    \
	}								    \
	struct __##var##__dummy_read {; } /* semicolon catcher */

#define LDLM_POOL_SYSFS_WRITER_STORE(var, type)				    \
	static ssize_t var##_store(struct kobject *kobj,		    \
				     struct attribute *attr,		    \
				     const char *buffer,		    \
				     size_t count)			    \
	{								    \
		struct ldlm_pool *pl = container_of(kobj, struct ldlm_pool, \
						    pl_kobj);		    \
		unsigned long tmp;					    \
		int rc;							    \
									    \
		rc = kstrtoul(buffer, 10, &tmp);			    \
		if (rc < 0) {						    \
			return rc;					    \
		}							    \
									    \
		spin_lock(&pl->pl_lock);				    \
		LDLM_POOL_SYSFS_SET_##type(pl->pl_##var, tmp);		    \
		spin_unlock(&pl->pl_lock);				    \
									    \
		return count;						    \
	}								    \
	struct __##var##__dummy_write {; } /* semicolon catcher */

#define LDLM_POOL_SYSFS_READER_NOLOCK_SHOW(var, type)			    \
	static ssize_t var##_show(struct kobject *kobj,		    \
				    struct attribute *attr,		    \
				    char *buf)				    \
	{								    \
		struct ldlm_pool *pl = container_of(kobj, struct ldlm_pool, \
						    pl_kobj);		    \
									    \
		return LDLM_POOL_SYSFS_PRINT_##type(pl->pl_##var);	    \
	}								    \
	struct __##var##__dummy_read {; } /* semicolon catcher */

#define LDLM_POOL_SYSFS_WRITER_NOLOCK_STORE(var, type)			    \
	static ssize_t var##_store(struct kobject *kobj,		    \
				     struct attribute *attr,		    \
				     const char *buffer,		    \
				     size_t count)			    \
	{								    \
		struct ldlm_pool *pl = container_of(kobj, struct ldlm_pool, \
						    pl_kobj);		    \
		unsigned long tmp;					    \
		int rc;							    \
									    \
		rc = kstrtoul(buffer, 10, &tmp);			    \
		if (rc < 0) {						    \
			return rc;					    \
		}							    \
									    \
		LDLM_POOL_SYSFS_SET_##type(pl->pl_##var, tmp);		    \
									    \
		return count;						    \
	}								    \
	struct __##var##__dummy_write {; } /* semicolon catcher */

static inline int is_granted_or_cancelled(struct ldlm_lock *lock)
{
	int ret = 0;

	lock_res_and_lock(lock);
	if ((lock->l_req_mode == lock->l_granted_mode) &&
	    !ldlm_is_cp_reqd(lock))
		ret = 1;
	else if (ldlm_is_failed(lock) || ldlm_is_cancel(lock))
		ret = 1;
	unlock_res_and_lock(lock);

	return ret;
}

typedef void (*ldlm_policy_wire_to_local_t)(const union ldlm_wire_policy_data *,
					    union ldlm_policy_data *);

typedef void (*ldlm_policy_local_to_wire_t)(const union ldlm_policy_data *,
					    union ldlm_wire_policy_data *);

void ldlm_plain_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy,
				     union ldlm_policy_data *lpolicy);
void ldlm_plain_policy_local_to_wire(const union ldlm_policy_data *lpolicy,
				     union ldlm_wire_policy_data *wpolicy);
void ldlm_ibits_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy,
				     union ldlm_policy_data *lpolicy);
void ldlm_ibits_policy_local_to_wire(const union ldlm_policy_data *lpolicy,
				     union ldlm_wire_policy_data *wpolicy);
void ldlm_extent_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy,
				      union ldlm_policy_data *lpolicy);
void ldlm_extent_policy_local_to_wire(const union ldlm_policy_data *lpolicy,
				      union ldlm_wire_policy_data *wpolicy);
void ldlm_flock_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy,
				     union ldlm_policy_data *lpolicy);
void ldlm_flock_policy_local_to_wire(const union ldlm_policy_data *lpolicy,
				     union ldlm_wire_policy_data *wpolicy);