Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
  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
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
/*
 * 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.sun.com/software/products/lustre/docs/GPLv2.pdf
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 * GPL HEADER END
 */
/*
 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 * Use is subject to license terms.
 *
 * Copyright (c) 2011, 2012, Intel Corporation.
 */
/*
 * This file is part of Lustre, http://www.lustre.org/
 * Lustre is a trademark of Sun Microsystems, Inc.
 *
 * lustre/include/lustre_lib.h
 *
 * Basic Lustre library routines.
 */

#ifndef _LUSTRE_LIB_H
#define _LUSTRE_LIB_H

/** \defgroup lib lib
 *
 * @{
 */

#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/types.h>
#include "../../include/linux/libcfs/libcfs.h"
#include "lustre/lustre_idl.h"
#include "lustre_ver.h"
#include "lustre_cfg.h"

/* target.c */
struct kstatfs;
struct ptlrpc_request;
struct obd_export;
struct lu_target;
struct l_wait_info;
#include "lustre_ha.h"
#include "lustre_net.h"

#define LI_POISON 0x5a5a5a5a
#if BITS_PER_LONG > 32
# define LL_POISON 0x5a5a5a5a5a5a5a5aL
#else
# define LL_POISON 0x5a5a5a5aL
#endif
#define LP_POISON ((void *)LL_POISON)

int target_pack_pool_reply(struct ptlrpc_request *req);
int do_set_info_async(struct obd_import *imp,
		      int opcode, int version,
		      u32 keylen, void *key,
		      u32 vallen, void *val,
		      struct ptlrpc_request_set *set);

#define OBD_RECOVERY_MAX_TIME (obd_timeout * 18) /* b13079 */
#define OBD_MAX_IOCTL_BUFFER CONFIG_LUSTRE_OBD_MAX_IOCTL_BUFFER

void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id);

/* client.c */

int client_sanobd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg);
struct client_obd *client_conn2cli(struct lustre_handle *conn);

struct md_open_data;
struct obd_client_handle {
	struct lustre_handle	 och_fh;
	struct lu_fid		 och_fid;
	struct md_open_data	*och_mod;
	struct lustre_handle	 och_lease_handle; /* open lock for lease */
	__u32			 och_magic;
	fmode_t			 och_flags;
};

#define OBD_CLIENT_HANDLE_MAGIC 0xd15ea5ed

/* statfs_pack.c */
void statfs_unpack(struct kstatfs *sfs, struct obd_statfs *osfs);

/*
 * For md echo client
 */
enum md_echo_cmd {
	ECHO_MD_CREATE       = 1, /* Open/Create file on MDT */
	ECHO_MD_MKDIR	= 2, /* Mkdir on MDT */
	ECHO_MD_DESTROY      = 3, /* Unlink file on MDT */
	ECHO_MD_RMDIR	= 4, /* Rmdir on MDT */
	ECHO_MD_LOOKUP       = 5, /* Lookup on MDT */
	ECHO_MD_GETATTR      = 6, /* Getattr on MDT */
	ECHO_MD_SETATTR      = 7, /* Setattr on MDT */
	ECHO_MD_ALLOC_FID    = 8, /* Get FIDs from MDT */
};

/*
 *   OBD IOCTLS
 */
#define OBD_IOCTL_VERSION 0x00010004

struct obd_ioctl_data {
	__u32 ioc_len;
	__u32 ioc_version;

	union {
		__u64 ioc_cookie;
		__u64 ioc_u64_1;
	};
	union {
		__u32 ioc_conn1;
		__u32 ioc_u32_1;
	};
	union {
		__u32 ioc_conn2;
		__u32 ioc_u32_2;
	};

	struct obdo ioc_obdo1;
	struct obdo ioc_obdo2;

	u64	 ioc_count;
	u64	 ioc_offset;
	__u32    ioc_dev;
	__u32    ioc_command;

	__u64 ioc_nid;
	__u32 ioc_nal;
	__u32 ioc_type;

	/* buffers the kernel will treat as user pointers */
	__u32  ioc_plen1;
	char  *ioc_pbuf1;
	__u32  ioc_plen2;
	char  *ioc_pbuf2;

	/* inline buffers for various arguments */
	__u32  ioc_inllen1;
	char  *ioc_inlbuf1;
	__u32  ioc_inllen2;
	char  *ioc_inlbuf2;
	__u32  ioc_inllen3;
	char  *ioc_inlbuf3;
	__u32  ioc_inllen4;
	char  *ioc_inlbuf4;

	char    ioc_bulk[0];
};

struct obd_ioctl_hdr {
	__u32 ioc_len;
	__u32 ioc_version;
};

static inline int obd_ioctl_packlen(struct obd_ioctl_data *data)
{
	int len = cfs_size_round(sizeof(struct obd_ioctl_data));

	len += cfs_size_round(data->ioc_inllen1);
	len += cfs_size_round(data->ioc_inllen2);
	len += cfs_size_round(data->ioc_inllen3);
	len += cfs_size_round(data->ioc_inllen4);
	return len;
}

static inline int obd_ioctl_is_invalid(struct obd_ioctl_data *data)
{
	if (data->ioc_len > OBD_MAX_IOCTL_BUFFER) {
		CERROR("OBD ioctl: ioc_len larger than %d\n",
		       OBD_MAX_IOCTL_BUFFER);
		return 1;
	}
	if (data->ioc_inllen1 > OBD_MAX_IOCTL_BUFFER) {
		CERROR("OBD ioctl: ioc_inllen1 larger than ioc_len\n");
		return 1;
	}
	if (data->ioc_inllen2 > OBD_MAX_IOCTL_BUFFER) {
		CERROR("OBD ioctl: ioc_inllen2 larger than ioc_len\n");
		return 1;
	}
	if (data->ioc_inllen3 > OBD_MAX_IOCTL_BUFFER) {
		CERROR("OBD ioctl: ioc_inllen3 larger than ioc_len\n");
		return 1;
	}
	if (data->ioc_inllen4 > OBD_MAX_IOCTL_BUFFER) {
		CERROR("OBD ioctl: ioc_inllen4 larger than ioc_len\n");
		return 1;
	}
	if (data->ioc_inlbuf1 && !data->ioc_inllen1) {
		CERROR("OBD ioctl: inlbuf1 pointer but 0 length\n");
		return 1;
	}
	if (data->ioc_inlbuf2 && !data->ioc_inllen2) {
		CERROR("OBD ioctl: inlbuf2 pointer but 0 length\n");
		return 1;
	}
	if (data->ioc_inlbuf3 && !data->ioc_inllen3) {
		CERROR("OBD ioctl: inlbuf3 pointer but 0 length\n");
		return 1;
	}
	if (data->ioc_inlbuf4 && !data->ioc_inllen4) {
		CERROR("OBD ioctl: inlbuf4 pointer but 0 length\n");
		return 1;
	}
	if (data->ioc_pbuf1 && !data->ioc_plen1) {
		CERROR("OBD ioctl: pbuf1 pointer but 0 length\n");
		return 1;
	}
	if (data->ioc_pbuf2 && !data->ioc_plen2) {
		CERROR("OBD ioctl: pbuf2 pointer but 0 length\n");
		return 1;
	}
	if (data->ioc_plen1 && !data->ioc_pbuf1) {
		CERROR("OBD ioctl: plen1 set but NULL pointer\n");
		return 1;
	}
	if (data->ioc_plen2 && !data->ioc_pbuf2) {
		CERROR("OBD ioctl: plen2 set but NULL pointer\n");
		return 1;
	}
	if (obd_ioctl_packlen(data) > data->ioc_len) {
		CERROR("OBD ioctl: packlen exceeds ioc_len (%d > %d)\n",
		       obd_ioctl_packlen(data), data->ioc_len);
		return 1;
	}
	return 0;
}

#include "obd_support.h"

/* function defined in lustre/obdclass/<platform>/<platform>-module.c */
int obd_ioctl_getdata(char **buf, int *len, void *arg);
int obd_ioctl_popdata(void *arg, void *data, int len);

static inline void obd_ioctl_freedata(char *buf, int len)
{
	kvfree(buf);
	return;
}

/*
 * BSD ioctl description:
 * #define IOC_V1       _IOR(g, n1, long)
 * #define IOC_V2       _IOW(g, n2, long)
 *
 * ioctl(f, IOC_V1, arg);
 * arg will be treated as a long value,
 *
 * ioctl(f, IOC_V2, arg)
 * arg will be treated as a pointer, bsd will call
 * copyin(buf, arg, sizeof(long))
 *
 * To make BSD ioctl handles argument correctly and simplely,
 * we change _IOR to _IOWR so BSD will copyin obd_ioctl_data
 * for us. Does this change affect Linux?  (XXX Liang)
 */
#define OBD_IOC_DATA_TYPE long

#define OBD_IOC_CREATE		 _IOWR('f', 101, OBD_IOC_DATA_TYPE)
#define OBD_IOC_DESTROY		_IOW ('f', 104, OBD_IOC_DATA_TYPE)
#define OBD_IOC_PREALLOCATE	    _IOWR('f', 105, OBD_IOC_DATA_TYPE)

#define OBD_IOC_SETATTR		_IOW ('f', 107, OBD_IOC_DATA_TYPE)
#define OBD_IOC_GETATTR		_IOWR ('f', 108, OBD_IOC_DATA_TYPE)
#define OBD_IOC_READ		   _IOWR('f', 109, OBD_IOC_DATA_TYPE)
#define OBD_IOC_WRITE		  _IOWR('f', 110, OBD_IOC_DATA_TYPE)

#define OBD_IOC_STATFS		 _IOWR('f', 113, OBD_IOC_DATA_TYPE)
#define OBD_IOC_SYNC		   _IOW ('f', 114, OBD_IOC_DATA_TYPE)
#define OBD_IOC_READ2		  _IOWR('f', 115, OBD_IOC_DATA_TYPE)
#define OBD_IOC_FORMAT		 _IOWR('f', 116, OBD_IOC_DATA_TYPE)
#define OBD_IOC_PARTITION	      _IOWR('f', 117, OBD_IOC_DATA_TYPE)
#define OBD_IOC_COPY		   _IOWR('f', 120, OBD_IOC_DATA_TYPE)
#define OBD_IOC_MIGR		   _IOWR('f', 121, OBD_IOC_DATA_TYPE)
#define OBD_IOC_PUNCH		  _IOWR('f', 122, OBD_IOC_DATA_TYPE)

#define OBD_IOC_MODULE_DEBUG	   _IOWR('f', 124, OBD_IOC_DATA_TYPE)
#define OBD_IOC_BRW_READ	       _IOWR('f', 125, OBD_IOC_DATA_TYPE)
#define OBD_IOC_BRW_WRITE	      _IOWR('f', 126, OBD_IOC_DATA_TYPE)
#define OBD_IOC_NAME2DEV	       _IOWR('f', 127, OBD_IOC_DATA_TYPE)
#define OBD_IOC_UUID2DEV	       _IOWR('f', 130, OBD_IOC_DATA_TYPE)

#define OBD_IOC_GETNAME		_IOWR('f', 131, OBD_IOC_DATA_TYPE)
#define OBD_IOC_GETMDNAME	      _IOR('f', 131, char[MAX_OBD_NAME])
#define OBD_IOC_GETDTNAME	       OBD_IOC_GETNAME

#define OBD_IOC_LOV_GET_CONFIG	 _IOWR('f', 132, OBD_IOC_DATA_TYPE)
#define OBD_IOC_CLIENT_RECOVER	 _IOW ('f', 133, OBD_IOC_DATA_TYPE)
#define OBD_IOC_PING_TARGET	    _IOW ('f', 136, OBD_IOC_DATA_TYPE)

#define OBD_IOC_DEC_FS_USE_COUNT       _IO  ('f', 139)
#define OBD_IOC_NO_TRANSNO	     _IOW ('f', 140, OBD_IOC_DATA_TYPE)
#define OBD_IOC_SET_READONLY	   _IOW ('f', 141, OBD_IOC_DATA_TYPE)
#define OBD_IOC_ABORT_RECOVERY	 _IOR ('f', 142, OBD_IOC_DATA_TYPE)

#define OBD_IOC_ROOT_SQUASH	    _IOWR('f', 143, OBD_IOC_DATA_TYPE)

#define OBD_GET_VERSION		_IOWR ('f', 144, OBD_IOC_DATA_TYPE)

#define OBD_IOC_GSS_SUPPORT	    _IOWR('f', 145, OBD_IOC_DATA_TYPE)

#define OBD_IOC_CLOSE_UUID	     _IOWR ('f', 147, OBD_IOC_DATA_TYPE)

#define OBD_IOC_CHANGELOG_SEND	 _IOW ('f', 148, OBD_IOC_DATA_TYPE)
#define OBD_IOC_GETDEVICE	      _IOWR ('f', 149, OBD_IOC_DATA_TYPE)
#define OBD_IOC_FID2PATH	       _IOWR ('f', 150, OBD_IOC_DATA_TYPE)
/* see also <lustre/lustre_user.h> for ioctls 151-153 */
/* OBD_IOC_LOV_SETSTRIPE: See also LL_IOC_LOV_SETSTRIPE */
#define OBD_IOC_LOV_SETSTRIPE	  _IOW ('f', 154, OBD_IOC_DATA_TYPE)
/* OBD_IOC_LOV_GETSTRIPE: See also LL_IOC_LOV_GETSTRIPE */
#define OBD_IOC_LOV_GETSTRIPE	  _IOW ('f', 155, OBD_IOC_DATA_TYPE)
/* OBD_IOC_LOV_SETEA: See also LL_IOC_LOV_SETEA */
#define OBD_IOC_LOV_SETEA	      _IOW ('f', 156, OBD_IOC_DATA_TYPE)
/* see <lustre/lustre_user.h> for ioctls 157-159 */
/* OBD_IOC_QUOTACHECK: See also LL_IOC_QUOTACHECK */
#define OBD_IOC_QUOTACHECK	     _IOW ('f', 160, int)
/* OBD_IOC_POLL_QUOTACHECK: See also LL_IOC_POLL_QUOTACHECK */
#define OBD_IOC_POLL_QUOTACHECK	_IOR ('f', 161, struct if_quotacheck *)
/* OBD_IOC_QUOTACTL: See also LL_IOC_QUOTACTL */
#define OBD_IOC_QUOTACTL	       _IOWR('f', 162, struct if_quotactl)
/* see  also <lustre/lustre_user.h> for ioctls 163-176 */
#define OBD_IOC_CHANGELOG_REG	  _IOW ('f', 177, struct obd_ioctl_data)
#define OBD_IOC_CHANGELOG_DEREG	_IOW ('f', 178, struct obd_ioctl_data)
#define OBD_IOC_CHANGELOG_CLEAR	_IOW ('f', 179, struct obd_ioctl_data)
#define OBD_IOC_RECORD		 _IOWR('f', 180, OBD_IOC_DATA_TYPE)
#define OBD_IOC_ENDRECORD	      _IOWR('f', 181, OBD_IOC_DATA_TYPE)
#define OBD_IOC_PARSE		  _IOWR('f', 182, OBD_IOC_DATA_TYPE)
#define OBD_IOC_DORECORD	       _IOWR('f', 183, OBD_IOC_DATA_TYPE)
#define OBD_IOC_PROCESS_CFG	    _IOWR('f', 184, OBD_IOC_DATA_TYPE)
#define OBD_IOC_DUMP_LOG	       _IOWR('f', 185, OBD_IOC_DATA_TYPE)
#define OBD_IOC_CLEAR_LOG	      _IOWR('f', 186, OBD_IOC_DATA_TYPE)
#define OBD_IOC_PARAM		  _IOW ('f', 187, OBD_IOC_DATA_TYPE)
#define OBD_IOC_POOL		   _IOWR('f', 188, OBD_IOC_DATA_TYPE)
#define OBD_IOC_REPLACE_NIDS	   _IOWR('f', 189, OBD_IOC_DATA_TYPE)

#define OBD_IOC_CATLOGLIST	     _IOWR('f', 190, OBD_IOC_DATA_TYPE)
#define OBD_IOC_LLOG_INFO	      _IOWR('f', 191, OBD_IOC_DATA_TYPE)
#define OBD_IOC_LLOG_PRINT	     _IOWR('f', 192, OBD_IOC_DATA_TYPE)
#define OBD_IOC_LLOG_CANCEL	    _IOWR('f', 193, OBD_IOC_DATA_TYPE)
#define OBD_IOC_LLOG_REMOVE	    _IOWR('f', 194, OBD_IOC_DATA_TYPE)
#define OBD_IOC_LLOG_CHECK	     _IOWR('f', 195, OBD_IOC_DATA_TYPE)
/* OBD_IOC_LLOG_CATINFO is deprecated */
#define OBD_IOC_LLOG_CATINFO	   _IOWR('f', 196, OBD_IOC_DATA_TYPE)

#define ECHO_IOC_GET_STRIPE	    _IOWR('f', 200, OBD_IOC_DATA_TYPE)
#define ECHO_IOC_SET_STRIPE	    _IOWR('f', 201, OBD_IOC_DATA_TYPE)
#define ECHO_IOC_ENQUEUE	       _IOWR('f', 202, OBD_IOC_DATA_TYPE)
#define ECHO_IOC_CANCEL		_IOWR('f', 203, OBD_IOC_DATA_TYPE)

#define OBD_IOC_GET_OBJ_VERSION	_IOR('f', 210, OBD_IOC_DATA_TYPE)

/* <lustre/lustre_user.h> defines ioctl number 218-219 */
#define OBD_IOC_GET_MNTOPT	     _IOW('f', 220, mntopt_t)

#define OBD_IOC_ECHO_MD		_IOR('f', 221, struct obd_ioctl_data)
#define OBD_IOC_ECHO_ALLOC_SEQ	 _IOWR('f', 222, struct obd_ioctl_data)

#define OBD_IOC_START_LFSCK	       _IOWR('f', 230, OBD_IOC_DATA_TYPE)
#define OBD_IOC_STOP_LFSCK	       _IOW('f', 231, OBD_IOC_DATA_TYPE)
#define OBD_IOC_PAUSE_LFSCK	       _IOW('f', 232, OBD_IOC_DATA_TYPE)

/* XXX _IOWR('f', 250, long) has been defined in
 * libcfs/include/libcfs/libcfs_private.h for debug, don't use it
 */

/* Until such time as we get_info the per-stripe maximum from the OST,
 * we define this to be 2T - 4k, which is the ext3 maxbytes. */
#define LUSTRE_STRIPE_MAXBYTES 0x1fffffff000ULL

/* Special values for remove LOV EA from disk */
#define LOVEA_DELETE_VALUES(size, count, offset) (size == 0 && count == 0 && \
						 offset == (typeof(offset))(-1))

/* #define POISON_BULK 0 */

/*
 * l_wait_event is a flexible sleeping function, permitting simple caller
 * configuration of interrupt and timeout sensitivity along with actions to
 * be performed in the event of either exception.
 *
 * The first form of usage looks like this:
 *
 * struct l_wait_info lwi = LWI_TIMEOUT_INTR(timeout, timeout_handler,
 *					   intr_handler, callback_data);
 * rc = l_wait_event(waitq, condition, &lwi);
 *
 * l_wait_event() makes the current process wait on 'waitq' until 'condition'
 * is TRUE or a "killable" signal (SIGTERM, SIKGILL, SIGINT) is pending.  It
 * returns 0 to signify 'condition' is TRUE, but if a signal wakes it before
 * 'condition' becomes true, it optionally calls the specified 'intr_handler'
 * if not NULL, and returns -EINTR.
 *
 * If a non-zero timeout is specified, signals are ignored until the timeout
 * has expired.  At this time, if 'timeout_handler' is not NULL it is called.
 * If it returns FALSE l_wait_event() continues to wait as described above with
 * signals enabled.  Otherwise it returns -ETIMEDOUT.
 *
 * LWI_INTR(intr_handler, callback_data) is shorthand for
 * LWI_TIMEOUT_INTR(0, NULL, intr_handler, callback_data)
 *
 * The second form of usage looks like this:
 *
 * struct l_wait_info lwi = LWI_TIMEOUT(timeout, timeout_handler);
 * rc = l_wait_event(waitq, condition, &lwi);
 *
 * This form is the same as the first except that it COMPLETELY IGNORES
 * SIGNALS.  The caller must therefore beware that if 'timeout' is zero, or if
 * 'timeout_handler' is not NULL and returns FALSE, then the ONLY thing that
 * can unblock the current process is 'condition' becoming TRUE.
 *
 * Another form of usage is:
 * struct l_wait_info lwi = LWI_TIMEOUT_INTERVAL(timeout, interval,
 *					       timeout_handler);
 * rc = l_wait_event(waitq, condition, &lwi);
 * This is the same as previous case, but condition is checked once every
 * 'interval' jiffies (if non-zero).
 *
 * Subtle synchronization point: this macro does *not* necessary takes
 * wait-queue spin-lock before returning, and, hence, following idiom is safe
 * ONLY when caller provides some external locking:
 *
 *	     Thread1			    Thread2
 *
 *   l_wait_event(&obj->wq, ....);				       (1)
 *
 *				    wake_up(&obj->wq):		 (2)
 *					 spin_lock(&q->lock);	  (2.1)
 *					 __wake_up_common(q, ...);     (2.2)
 *					 spin_unlock(&q->lock, flags); (2.3)
 *
 *   kfree(obj);						  (3)
 *
 * As l_wait_event() may "short-cut" execution and return without taking
 * wait-queue spin-lock, some additional synchronization is necessary to
 * guarantee that step (3) can begin only after (2.3) finishes.
 *
 * XXX nikita: some ptlrpc daemon threads have races of that sort.
 *
 */
static inline int back_to_sleep(void *arg)
{
	return 0;
}

#define LWI_ON_SIGNAL_NOOP ((void (*)(void *))(-1))

struct l_wait_info {
	long lwi_timeout;
	long lwi_interval;
	int	    lwi_allow_intr;
	int  (*lwi_on_timeout)(void *);
	void (*lwi_on_signal)(void *);
	void  *lwi_cb_data;
};

/* NB: LWI_TIMEOUT ignores signals completely */
#define LWI_TIMEOUT(time, cb, data)	     \
((struct l_wait_info) {			 \
	.lwi_timeout    = time,		 \
	.lwi_on_timeout = cb,		   \
	.lwi_cb_data    = data,		 \
	.lwi_interval   = 0,		    \
	.lwi_allow_intr = 0		     \
})

#define LWI_TIMEOUT_INTERVAL(time, interval, cb, data)  \
((struct l_wait_info) {				 \
	.lwi_timeout    = time,			 \
	.lwi_on_timeout = cb,			   \
	.lwi_cb_data    = data,			 \
	.lwi_interval   = interval,		     \
	.lwi_allow_intr = 0			     \
})

#define LWI_TIMEOUT_INTR(time, time_cb, sig_cb, data)   \
((struct l_wait_info) {				 \
	.lwi_timeout    = time,			 \
	.lwi_on_timeout = time_cb,		      \
	.lwi_on_signal  = sig_cb,		       \
	.lwi_cb_data    = data,			 \
	.lwi_interval   = 0,			    \
	.lwi_allow_intr = 0			     \
})

#define LWI_TIMEOUT_INTR_ALL(time, time_cb, sig_cb, data)       \
((struct l_wait_info) {					 \
	.lwi_timeout    = time,				 \
	.lwi_on_timeout = time_cb,			      \
	.lwi_on_signal  = sig_cb,			       \
	.lwi_cb_data    = data,				 \
	.lwi_interval   = 0,				    \
	.lwi_allow_intr = 1				     \
})

#define LWI_INTR(cb, data)  LWI_TIMEOUT_INTR(0, NULL, cb, data)

#define LUSTRE_FATAL_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) |		\
			   sigmask(SIGTERM) | sigmask(SIGQUIT) |	\
			   sigmask(SIGALRM))

/*
 * wait for @condition to become true, but no longer than timeout, specified
 * by @info.
 */
#define __l_wait_event(wq, condition, info, ret, l_add_wait)		   \
do {									   \
	wait_queue_t __wait;						 \
	long __timeout = info->lwi_timeout;			  \
	sigset_t   __blocked;					      \
	int   __allow_intr = info->lwi_allow_intr;			     \
									       \
	ret = 0;							       \
	if (condition)							 \
		break;							 \
									       \
	init_waitqueue_entry(&__wait, current);					    \
	l_add_wait(&wq, &__wait);					      \
									       \
	/* Block all signals (just the non-fatal ones if no timeout). */       \
	if (info->lwi_on_signal != NULL && (__timeout == 0 || __allow_intr))   \
		__blocked = cfs_block_sigsinv(LUSTRE_FATAL_SIGS);	      \
	else								   \
		__blocked = cfs_block_sigsinv(0);			      \
									       \
	for (;;) {							     \
		if (condition)						 \
			break;						 \
									       \
		set_current_state(TASK_INTERRUPTIBLE);			       \
									       \
		if (__timeout == 0) {					  \
			schedule();					       \
		} else {						       \
			long interval = info->lwi_interval ?	  \
					     min_t(long,	     \
						 info->lwi_interval, __timeout) : \
					     __timeout;			\
			long remaining = schedule_timeout(interval);\
			__timeout = cfs_time_sub(__timeout,		    \
					    cfs_time_sub(interval, remaining));\
			if (__timeout == 0) {				  \
				if (info->lwi_on_timeout == NULL ||	    \
				    info->lwi_on_timeout(info->lwi_cb_data)) { \
					ret = -ETIMEDOUT;		      \
					break;				 \
				}					      \
				/* Take signals after the timeout expires. */  \
				if (info->lwi_on_signal != NULL)	       \
				    (void)cfs_block_sigsinv(LUSTRE_FATAL_SIGS);\
			}						      \
		}							      \
									       \
		set_current_state(TASK_RUNNING);			       \
									       \
		if (condition)						 \
			break;						 \
		if (cfs_signal_pending()) {				    \
			if (info->lwi_on_signal != NULL &&		     \
			    (__timeout == 0 || __allow_intr)) {		\
				if (info->lwi_on_signal != LWI_ON_SIGNAL_NOOP) \
					info->lwi_on_signal(info->lwi_cb_data);\
				ret = -EINTR;				  \
				break;					 \
			}						      \
			/* We have to do this here because some signals */     \
			/* are not blockable - ie from strace(1).       */     \
			/* In these cases we want to schedule_timeout() */     \
			/* again, because we don't want that to return  */     \
			/* -EINTR when the RPC actually succeeded.      */     \
			/* the recalc_sigpending() below will deliver the */     \
			/* signal properly.			     */     \
			cfs_clear_sigpending();				\
		}							      \
	}								      \
									       \
	cfs_restore_sigs(__blocked);					   \
									       \
	remove_wait_queue(&wq, &__wait);					   \
} while (0)

#define l_wait_event(wq, condition, info)		       \
({							      \
	int		 __ret;			      \
	struct l_wait_info *__info = (info);		    \
								\
	__l_wait_event(wq, condition, __info,		   \
		       __ret, add_wait_queue);		   \
	__ret;						  \
})

#define l_wait_event_exclusive(wq, condition, info)	     \
({							      \
	int		 __ret;			      \
	struct l_wait_info *__info = (info);		    \
								\
	__l_wait_event(wq, condition, __info,		   \
		       __ret, add_wait_queue_exclusive);	 \
	__ret;						  \
})

#define l_wait_event_exclusive_head(wq, condition, info)	\
({							      \
	int		 __ret;			      \
	struct l_wait_info *__info = (info);		    \
								\
	__l_wait_event(wq, condition, __info,		   \
		       __ret, add_wait_queue_exclusive_head);    \
	__ret;						  \
})

#define l_wait_condition(wq, condition)			 \
({							      \
	struct l_wait_info lwi = { 0 };			 \
	l_wait_event(wq, condition, &lwi);		      \
})

#define l_wait_condition_exclusive(wq, condition)	       \
({							      \
	struct l_wait_info lwi = { 0 };			 \
	l_wait_event_exclusive(wq, condition, &lwi);	    \
})

#define l_wait_condition_exclusive_head(wq, condition)	  \
({							      \
	struct l_wait_info lwi = { 0 };			 \
	l_wait_event_exclusive_head(wq, condition, &lwi);       \
})

#define LIBLUSTRE_CLIENT (0)

/** @} lib */

#endif /* _LUSTRE_LIB_H */