summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.h
blob: 154990c26dcbc9d63508228b9125182b7168b80e (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
/*
 * Copyright (C) 2008 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License v2 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 for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#ifndef __TREE_LOG_
#define __TREE_LOG_

#include "ctree.h"
#include "transaction.h"

/* return value for btrfs_log_dentry_safe that means we don't need to log it at all */
#define BTRFS_NO_LOG_SYNC 256

struct btrfs_log_ctx {
	int log_ret;
	int log_transid;
	int io_err;
	struct list_head list;
};

static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx)
{
	ctx->log_ret = 0;
	ctx->log_transid = 0;
	ctx->io_err = 0;
	INIT_LIST_HEAD(&ctx->list);
}

static inline void btrfs_set_log_full_commit(struct btrfs_fs_info *fs_info,
					     struct btrfs_trans_handle *trans)
{
	ACCESS_ONCE(fs_info->last_trans_log_full_commit) = trans->transid;
}

static inline int btrfs_need_log_full_commit(struct btrfs_fs_info *fs_info,
					     struct btrfs_trans_handle *trans)
{
	return ACCESS_ONCE(fs_info->last_trans_log_full_commit) ==
		trans->transid;
}

int btrfs_sync_log(struct btrfs_trans_handle *trans,
		   struct btrfs_root *root, struct btrfs_log_ctx *ctx);
int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
			     struct btrfs_fs_info *fs_info);
int btrfs_recover_log_trees(struct btrfs_root *tree_root);
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
			  struct btrfs_root *root, struct dentry *dentry,
			  const loff_t start,
			  const loff_t end,
			  struct btrfs_log_ctx *ctx);
int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
				 struct btrfs_root *root,
				 const char *name, int name_len,
				 struct inode *dir, u64 index);
int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
			       struct btrfs_root *root,
			       const char *name, int name_len,
			       struct inode *inode, u64 dirid);
void btrfs_end_log_trans(struct btrfs_root *root);
int btrfs_pin_log_trans(struct btrfs_root *root);
void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
			     struct inode *dir, struct inode *inode,
			     int for_rename);
int btrfs_log_new_name(struct btrfs_trans_handle *trans,
			struct inode *inode, struct inode *old_dir,
			struct dentry *parent);
#endif
ter Linus Torvalds <torvalds@linux-foundation.org> 2008-07-24 13:47:34 -0400 rtc-at91rm9200: avoid spurious irqs' href='/cgit/cgit.cgi/litmus-rt-budgetable-locks.git/.git/commit/drivers/rtc/rtc-at91rm9200.c?h=update_litmus_2019&id=449321b39f6c6ebfa15d6da24f134240bd51db29'>449321b39f6c
5d4675a811fb
449321b39f6c
5d4675a811fb
2a4e2b8780c6
e7a8bb12c24a

788b1fc619a3






e7a8bb12c24a

788b1fc619a3


2a4e2b8780c6
788b1fc619a3
449321b39f6c
788b1fc619a3




449321b39f6c
788b1fc619a3


788b1fc619a3


449321b39f6c
788b1fc619a3

788b1fc619a3














e7a8bb12c24a





788b1fc619a3






7d12e780e003
788b1fc619a3
e7a8bb12c24a
788b1fc619a3












e7a8bb12c24a
788b1fc619a3
ab6a2d70d18e
788b1fc619a3
2a4e2b8780c6
788b1fc619a3






ff8371ac9a5a
788b1fc619a3



















e7a8bb12c24a


788b1fc619a3
e7a8bb12c24a
d728b1e69fd5

788b1fc619a3
e7a8bb12c24a

788b1fc619a3


5d4675a811fb





e7a8bb12c24a

788b1fc619a3












5d4675a811fb
788b1fc619a3



e7a8bb12c24a


788b1fc619a3











90b4d648f02a
788b1fc619a3


90b4d648f02a










788b1fc619a3




90b4d648f02a





788b1fc619a3







5d4675a811fb
788b1fc619a3









5d4675a811fb
788b1fc619a3






788b1fc619a3





ad28a07bcadc
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






























                                                                     
                          
 






                                                                                 


                                           

                                                                          






                                                

                                                         









                                                                      

                                                                             














                                                                                                     
                                                                  

                                                            










                                                                    
                                                                  

                                                            





                                                                            
                                                                               







                                                      



                                                                                                     



















                                                                               


                                                                      
                                                                  

                                                            


















                                                                         
                                                     









                                                                                   

                                                              
                                                             
         
 
                                                                  

                                                                   






                                  

                                                               


                    
                                                                     
 
                                                               




                                                             
                                                              


                                                             


                                                             
                                                              

                                                             














                                                                  





                                                                






                          
                                                            
 
                                              












                                                                            
                                                                              
 
                                               
 
                                                                     






                                                          
                                                  



















                                                                  


                                                                         
 
                                                          

                                                            
                  

                                                                     


                           





                                                                  

                                                            












                                                           
                                                               



                                                            


                                                                         











                                             
                        


                                                                             










                                                                      




                                                        





                                                                   







                                                 
                                                    









                                           
                                                                       






                                                     





                                                      
                                  
/*
 *	Real Time Clock interface for Linux on Atmel AT91RM9200
 *
 *	Copyright (C) 2002 Rick Bronson
 *
 *	Converted to RTC class model by Andrew Victor
 *
 *	Ported to Linux 2.6 by Steven Scholz
 *	Based on s3c2410-rtc.c Simtec Electronics
 *
 *	Based on sa1100-rtc.c by Nils Faerber
 *	Based on rtc.c by Paul Gortmaker
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 *
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/time.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/interrupt.h>
#include <linux/ioctl.h>
#include <linux/completion.h>

#include <asm/uaccess.h>
#include <mach/at91_rtc.h>


#define AT91_RTC_FREQ		1
#define AT91_RTC_EPOCH		1900UL	/* just like arch/arm/common/rtctime.c */

static DECLARE_COMPLETION(at91_rtc_updated);
static unsigned int at91_alarm_year = AT91_RTC_EPOCH;

/*
 * Decode time/date into rtc_time structure
 */
static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
				struct rtc_time *tm)
{
	unsigned int time, date;

	/* must read twice in case it changes */
	do {
		time = at91_sys_read(timereg);
		date = at91_sys_read(calreg);
	} while ((time != at91_sys_read(timereg)) ||
			(date != at91_sys_read(calreg)));

	tm->tm_sec  = BCD2BIN((time & AT91_RTC_SEC) >> 0);
	tm->tm_min  = BCD2BIN((time & AT91_RTC_MIN) >> 8);
	tm->tm_hour = BCD2BIN((time & AT91_RTC_HOUR) >> 16);

	/*
	 * The Calendar Alarm register does not have a field for
	 * the year - so these will return an invalid value.  When an
	 * alarm is set, at91_alarm_year wille store the current year.
	 */
	tm->tm_year  = BCD2BIN(date & AT91_RTC_CENT) * 100;	/* century */
	tm->tm_year += BCD2BIN((date & AT91_RTC_YEAR) >> 8);	/* year */

	tm->tm_wday = BCD2BIN((date & AT91_RTC_DAY) >> 21) - 1;	/* day of the week [0-6], Sunday=0 */
	tm->tm_mon  = BCD2BIN((date & AT91_RTC_MONTH) >> 16) - 1;
	tm->tm_mday = BCD2BIN((date & AT91_RTC_DATE) >> 24);
}

/*
 * Read current time and date in RTC
 */
static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
{
	at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, tm);
	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
	tm->tm_year = tm->tm_year - 1900;

	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
		tm->tm_hour, tm->tm_min, tm->tm_sec);

	return 0;
}

/*
 * Set current time and date in RTC
 */
static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
{
	unsigned long cr;

	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
		tm->tm_hour, tm->tm_min, tm->tm_sec);

	/* Stop Time/Calendar from counting */
	cr = at91_sys_read(AT91_RTC_CR);
	at91_sys_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);

	at91_sys_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
	wait_for_completion(&at91_rtc_updated);	/* wait for ACKUPD interrupt */
	at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);

	at91_sys_write(AT91_RTC_TIMR,
			  BIN2BCD(tm->tm_sec) << 0
			| BIN2BCD(tm->tm_min) << 8
			| BIN2BCD(tm->tm_hour) << 16);

	at91_sys_write(AT91_RTC_CALR,
			  BIN2BCD((tm->tm_year + 1900) / 100)	/* century */
			| BIN2BCD(tm->tm_year % 100) << 8	/* year */
			| BIN2BCD(tm->tm_mon + 1) << 16		/* tm_mon starts at zero */
			| BIN2BCD(tm->tm_wday + 1) << 21	/* day of the week [0-6], Sunday=0 */
			| BIN2BCD(tm->tm_mday) << 24);

	/* Restart Time/Calendar */
	cr = at91_sys_read(AT91_RTC_CR);
	at91_sys_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));

	return 0;
}

/*
 * Read alarm time and date in RTC
 */
static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct rtc_time *tm = &alrm->time;

	at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
	tm->tm_year = at91_alarm_year - 1900;

	alrm->enabled = (at91_sys_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
			? 1 : 0;

	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
		tm->tm_hour, tm->tm_min, tm->tm_sec);

	return 0;
}

/*
 * Set alarm time and date in RTC
 */
static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct rtc_time tm;

	at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);

	at91_alarm_year = tm.tm_year;

	tm.tm_hour = alrm->time.tm_hour;
	tm.tm_min = alrm->time.tm_min;
	tm.tm_sec = alrm->time.tm_sec;

	at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
	at91_sys_write(AT91_RTC_TIMALR,
		  BIN2BCD(tm.tm_sec) << 0
		| BIN2BCD(tm.tm_min) << 8
		| BIN2BCD(tm.tm_hour) << 16
		| AT91_RTC_HOUREN | AT91_RTC_MINEN | AT91_RTC_SECEN);
	at91_sys_write(AT91_RTC_CALALR,
		  BIN2BCD(tm.tm_mon + 1) << 16		/* tm_mon starts at zero */
		| BIN2BCD(tm.tm_mday) << 24
		| AT91_RTC_DATEEN | AT91_RTC_MTHEN);

	if (alrm->enabled) {
		at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
		at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
	}

	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
		at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
		tm.tm_min, tm.tm_sec);

	return 0;
}

/*
 * Handle commands from user-space
 */
static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
			unsigned long arg)
{
	int ret = 0;

	pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg);

	/* important:  scrub old status before enabling IRQs */
	switch (cmd) {
	case RTC_AIE_OFF:	/* alarm off */
		at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
		break;
	case RTC_AIE_ON:	/* alarm on */
		at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
		at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
		break;
	case RTC_UIE_OFF:	/* update off */
		at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
		break;
	case RTC_UIE_ON:	/* update on */
		at91_sys_write(AT91_RTC_SCCR, AT91_RTC_SECEV);
		at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV);
		break;
	default:
		ret = -ENOIOCTLCMD;
		break;
	}

	return ret;
}

/*
 * Provide additional RTC information in /proc/driver/rtc
 */
static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
{
	unsigned long imr = at91_sys_read(AT91_RTC_IMR);

	seq_printf(seq, "update_IRQ\t: %s\n",
			(imr & AT91_RTC_ACKUPD) ? "yes" : "no");
	seq_printf(seq, "periodic_IRQ\t: %s\n",
			(imr & AT91_RTC_SECEV) ? "yes" : "no");
	seq_printf(seq, "periodic_freq\t: %ld\n",
			(unsigned long) AT91_RTC_FREQ);

	return 0;
}

/*
 * IRQ handler for the RTC
 */
static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
{
	struct platform_device *pdev = dev_id;
	struct rtc_device *rtc = platform_get_drvdata(pdev);
	unsigned int rtsr;
	unsigned long events = 0;

	rtsr = at91_sys_read(AT91_RTC_SR) & at91_sys_read(AT91_RTC_IMR);
	if (rtsr) {		/* this interrupt is shared!  Is it ours? */
		if (rtsr & AT91_RTC_ALARM)
			events |= (RTC_AF | RTC_IRQF);
		if (rtsr & AT91_RTC_SECEV)
			events |= (RTC_UF | RTC_IRQF);
		if (rtsr & AT91_RTC_ACKUPD)
			complete(&at91_rtc_updated);

		at91_sys_write(AT91_RTC_SCCR, rtsr);	/* clear status reg */

		rtc_update_irq(rtc, 1, events);

		pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__,
			events >> 8, events & 0x000000FF);

		return IRQ_HANDLED;
	}
	return IRQ_NONE;		/* not handled */
}

static const struct rtc_class_ops at91_rtc_ops = {
	.ioctl		= at91_rtc_ioctl,
	.read_time	= at91_rtc_readtime,
	.set_time	= at91_rtc_settime,
	.read_alarm	= at91_rtc_readalarm,
	.set_alarm	= at91_rtc_setalarm,
	.proc		= at91_rtc_proc,
};

/*
 * Initialize and install RTC driver
 */
static int __init at91_rtc_probe(struct platform_device *pdev)
{
	struct rtc_device *rtc;
	int ret;

	at91_sys_write(AT91_RTC_CR, 0);
	at91_sys_write(AT91_RTC_MR, 0);		/* 24 hour mode */

	/* Disable all interrupts */
	at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
					AT91_RTC_SECEV | AT91_RTC_TIMEV |
					AT91_RTC_CALEV);

	ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
				IRQF_DISABLED | IRQF_SHARED,
				"at91_rtc", pdev);
	if (ret) {
		printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
				AT91_ID_SYS);
		return ret;
	}

	/* cpu init code should really have flagged this device as
	 * being wake-capable; if it didn't, do that here.
	 */
	if (!device_can_wakeup(&pdev->dev))
		device_init_wakeup(&pdev->dev, 1);

	rtc = rtc_device_register(pdev->name, &pdev->dev,
				&at91_rtc_ops, THIS_MODULE);
	if (IS_ERR(rtc)) {
		free_irq(AT91_ID_SYS, pdev);
		return PTR_ERR(rtc);
	}
	platform_set_drvdata(pdev, rtc);

	printk(KERN_INFO "AT91 Real Time Clock driver.\n");
	return 0;
}

/*
 * Disable and remove the RTC driver
 */
static int __exit at91_rtc_remove(struct platform_device *pdev)
{
	struct rtc_device *rtc = platform_get_drvdata(pdev);

	/* Disable all interrupts */
	at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
					AT91_RTC_SECEV | AT91_RTC_TIMEV |
					AT91_RTC_CALEV);
	free_irq(AT91_ID_SYS, pdev);

	rtc_device_unregister(rtc);
	platform_set_drvdata(pdev, NULL);

	return 0;
}

#ifdef CONFIG_PM

/* AT91RM9200 RTC Power management control */

static u32 at91_rtc_imr;

static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
	/* this IRQ is shared with DBGU and other hardware which isn't
	 * necessarily doing PM like we are...
	 */
	at91_rtc_imr = at91_sys_read(AT91_RTC_IMR)
			& (AT91_RTC_ALARM|AT91_RTC_SECEV);
	if (at91_rtc_imr) {
		if (device_may_wakeup(&pdev->dev))
			enable_irq_wake(AT91_ID_SYS);
		else
			at91_sys_write(AT91_RTC_IDR, at91_rtc_imr);
	}
	return 0;
}

static int at91_rtc_resume(struct platform_device *pdev)
{
	if (at91_rtc_imr) {
		if (device_may_wakeup(&pdev->dev))
			disable_irq_wake(AT91_ID_SYS);
		else
			at91_sys_write(AT91_RTC_IER, at91_rtc_imr);
	}
	return 0;
}
#else
#define at91_rtc_suspend NULL
#define at91_rtc_resume  NULL
#endif

static struct platform_driver at91_rtc_driver = {
	.remove		= __exit_p(at91_rtc_remove),
	.suspend	= at91_rtc_suspend,
	.resume		= at91_rtc_resume,
	.driver		= {
		.name	= "at91_rtc",
		.owner	= THIS_MODULE,
	},
};

static int __init at91_rtc_init(void)
{
	return platform_driver_probe(&at91_rtc_driver, at91_rtc_probe);
}

static void __exit at91_rtc_exit(void)
{
	platform_driver_unregister(&at91_rtc_driver);
}

module_init(at91_rtc_init);
module_exit(at91_rtc_exit);

MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:at91_rtc");