2 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 * Written 1992,1993 by Werner Almesberger
22 * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
23 * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
26 /************************************************************************/
28 /* PROJECT : exFAT & FAT12/16/32 File System */
30 /* PURPOSE : Helper function for checksum and handing sdFAT error */
32 /*----------------------------------------------------------------------*/
36 /************************************************************************/
38 #include <linux/module.h>
40 #include <linux/buffer_head.h>
41 #include <linux/time.h>
45 #ifdef CONFIG_SDFAT_SUPPORT_STLOG
46 #include <linux/stlog.h>
48 #define ST_LOG(fmt, ...)
52 * sdfat_fs_error reports a file system problem that might indicate fa data
53 * corruption/inconsistency. Depending on 'errors' mount option the
54 * panic() is called, or error message is printed FAT and nothing is done,
55 * or filesystem is remounted read-only (default behavior).
56 * In case the file system is remounted read-only, it can be made writable
57 * again by remounting it.
59 void __sdfat_fs_error(struct super_block
*sb
, int report
, const char *fmt
, ...)
61 struct sdfat_mount_options
*opts
= &SDFAT_SB(sb
)->options
;
64 struct block_device
*bdev
= sb
->s_bdev
;
65 dev_t bd_dev
= bdev
? bdev
->bd_dev
: 0;
71 pr_err("[SDFAT](%s[%d:%d]):ERR: %pV\n",
72 sb
->s_id
, MAJOR(bd_dev
), MINOR(bd_dev
), &vaf
);
73 #ifdef CONFIG_SDFAT_SUPPORT_STLOG
74 if (opts
->errors
== SDFAT_ERRORS_RO
&& !(sb
->s_flags
& MS_RDONLY
)) {
75 ST_LOG("[SDFAT](%s[%d:%d]):ERR: %pV\n",
76 sb
->s_id
, MAJOR(bd_dev
), MINOR(bd_dev
), &vaf
);
82 if (opts
->errors
== SDFAT_ERRORS_PANIC
) {
83 panic("[SDFAT](%s[%d:%d]): fs panic from previous error\n",
84 sb
->s_id
, MAJOR(bd_dev
), MINOR(bd_dev
));
85 } else if (opts
->errors
== SDFAT_ERRORS_RO
&& !(sb
->s_flags
& MS_RDONLY
)) {
86 sb
->s_flags
|= MS_RDONLY
;
87 pr_err("[SDFAT](%s[%d:%d]): Filesystem has been set "
88 "read-only\n", sb
->s_id
, MAJOR(bd_dev
), MINOR(bd_dev
));
89 #ifdef CONFIG_SDFAT_SUPPORT_STLOG
90 ST_LOG("[SDFAT](%s[%d:%d]): Filesystem has been set read-only\n",
91 sb
->s_id
, MAJOR(bd_dev
), MINOR(bd_dev
));
95 EXPORT_SYMBOL(__sdfat_fs_error
);
98 * __sdfat_msg() - print preformated SDFAT specific messages.
99 * All logs except what uses sdfat_fs_error() should be written by __sdfat_msg()
100 * If 'st' is set, the log is propagated to ST_LOG.
102 void __sdfat_msg(struct super_block
*sb
, const char *level
, int st
, const char *fmt
, ...)
104 struct va_format vaf
;
106 struct block_device
*bdev
= sb
->s_bdev
;
107 dev_t bd_dev
= bdev
? bdev
->bd_dev
: 0;
112 /* level means KERN_ pacility level */
113 printk("%s[SDFAT](%s[%d:%d]): %pV\n", level
,
114 sb
->s_id
, MAJOR(bd_dev
), MINOR(bd_dev
), &vaf
);
115 #ifdef CONFIG_SDFAT_SUPPORT_STLOG
117 ST_LOG("[SDFAT](%s[%d:%d]): %pV\n",
118 sb
->s_id
, MAJOR(bd_dev
), MINOR(bd_dev
), &vaf
);
123 EXPORT_SYMBOL(__sdfat_msg
);
125 void sdfat_log_version(void)
127 pr_info("[SDFAT] Filesystem version %s\n", SDFAT_VERSION
);
128 #ifdef CONFIG_SDFAT_SUPPORT_STLOG
129 ST_LOG("[SDFAT] Filesystem version %s\n", SDFAT_VERSION
);
132 EXPORT_SYMBOL(sdfat_log_version
);
134 /* <linux/time.h> externs sys_tz
135 * extern struct timezone sys_tz;
137 #define UNIX_SECS_1980 315532800L
139 #if BITS_PER_LONG == 64
140 #define UNIX_SECS_2108 4354819200L
143 /* days between 1970/01/01 and 1980/01/01 (2 leap days) */
144 #define DAYS_DELTA_DECADE (365 * 10 + 2)
145 /* 120 (2100 - 1980) isn't leap year */
146 #define NO_LEAP_YEAR_2100 (120)
147 #define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100)
149 #define SECS_PER_MIN (60)
150 #define SECS_PER_HOUR (60 * SECS_PER_MIN)
151 #define SECS_PER_DAY (24 * SECS_PER_HOUR)
153 #define MAKE_LEAP_YEAR(leap_year, year) \
155 /* 2100 isn't leap year */ \
156 if (unlikely(year > NO_LEAP_YEAR_2100)) \
157 leap_year = ((year + 3) / 4) - 1; \
159 leap_year = ((year + 3) / 4); \
162 /* Linear day numbers of the respective 1sts in non-leap years. */
163 static time_t accum_days_in_year
[] = {
164 /* Month : N 01 02 03 04 05 06 07 08 09 10 11 12 */
165 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
168 /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
169 void sdfat_time_fat2unix(struct sdfat_sb_info
*sbi
, struct timespec
*ts
,
172 time_t year
= tp
->Year
;
173 time_t ld
; /* leap day */
175 MAKE_LEAP_YEAR(ld
, year
);
177 if (IS_LEAP_YEAR(year
) && (tp
->Month
) > 2)
180 ts
->tv_sec
= tp
->Second
+ tp
->Minute
* SECS_PER_MIN
181 + tp
->Hour
* SECS_PER_HOUR
182 + (year
* 365 + ld
+ accum_days_in_year
[tp
->Month
]
183 + (tp
->Day
- 1) + DAYS_DELTA_DECADE
) * SECS_PER_DAY
;
185 if (!sbi
->options
.tz_utc
)
186 ts
->tv_sec
+= sys_tz
.tz_minuteswest
* SECS_PER_MIN
;
191 /* Convert linear UNIX date to a FAT time/date pair. */
192 void sdfat_time_unix2fat(struct sdfat_sb_info
*sbi
, struct timespec
*ts
,
195 time_t second
= ts
->tv_sec
;
196 time_t day
, month
, year
;
197 time_t ld
; /* leap day */
199 if (!sbi
->options
.tz_utc
)
200 second
-= sys_tz
.tz_minuteswest
* SECS_PER_MIN
;
202 /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
203 if (second
< UNIX_SECS_1980
) {
212 #if (BITS_PER_LONG == 64)
213 if (second
>= UNIX_SECS_2108
) {
224 day
= second
/ SECS_PER_DAY
- DAYS_DELTA_DECADE
;
227 MAKE_LEAP_YEAR(ld
, year
);
228 if (year
* 365 + ld
> day
)
231 MAKE_LEAP_YEAR(ld
, year
);
232 day
-= year
* 365 + ld
;
234 if (IS_LEAP_YEAR(year
) && day
== accum_days_in_year
[3]) {
237 if (IS_LEAP_YEAR(year
) && day
> accum_days_in_year
[3])
239 for (month
= 1; month
< 12; month
++) {
240 if (accum_days_in_year
[month
+ 1] > day
)
244 day
-= accum_days_in_year
[month
];
246 tp
->Second
= second
% SECS_PER_MIN
;
247 tp
->Minute
= (second
/ SECS_PER_MIN
) % 60;
248 tp
->Hour
= (second
/ SECS_PER_HOUR
) % 24;
254 TIMESTAMP_T
*tm_now(struct sdfat_sb_info
*sbi
, TIMESTAMP_T
*tp
)
256 struct timespec ts
= CURRENT_TIME_SEC
;
259 sdfat_time_unix2fat(sbi
, &ts
, &dt
);
271 u8
calc_chksum_1byte(void *data
, s32 len
, u8 chksum
)
276 for (i
= 0; i
< len
; i
++, c
++)
277 chksum
= (((chksum
& 1) << 7) | ((chksum
& 0xFE) >> 1)) + *c
;
282 u16
calc_chksum_2byte(void *data
, s32 len
, u16 chksum
, s32 type
)
287 for (i
= 0; i
< len
; i
++, c
++) {
288 if (((i
== 2) || (i
== 3)) && (type
== CS_DIR_ENTRY
))
290 chksum
= (((chksum
& 1) << 15) | ((chksum
& 0xFFFE) >> 1)) + (u16
) *c
;
295 #ifdef CONFIG_SDFAT_TRACE_ELAPSED_TIME
296 struct timeval __t1
, __t2
;
297 u32
sdfat_time_current_usec(struct timeval
*tv
)
300 return (u32
)(tv
->tv_sec
*1000000 + tv
->tv_usec
);
302 #endif /* CONFIG_SDFAT_TRACE_ELAPSED_TIME */
304 #ifdef CONFIG_SDFAT_DBG_CAREFUL
305 /* Check the consistency of i_size_ondisk (FAT32, or flags 0x01 only) */
306 void sdfat_debug_check_clusters(struct inode
*inode
)
309 volatile uint32_t tmp_fat_chain
[50];
310 volatile int num_clusters_org
, tmp_i
= 0;
312 FILE_ID_T
*fid
= &(SDFAT_I(inode
)->fid
);
313 FS_INFO_T
*fsi
= &(SDFAT_SB(inode
->i_sb
)->fsi
);
315 if (SDFAT_I(inode
)->i_size_ondisk
== 0)
318 num_clusters
= (s32
)((SDFAT_I(inode
)->i_size_ondisk
-1) >> fsi
->cluster_size_bits
) + 1;
320 clu
.dir
= fid
->start_clu
;
321 clu
.size
= num_clusters
;
322 clu
.flags
= fid
->flags
;
324 num_clusters_org
= num_clusters
;
326 if (clu
.flags
== 0x03)
329 while (num_clusters
> 0) {
330 /* FAT chain logging */
331 tmp_fat_chain
[tmp_i
] = clu
.dir
;
336 BUG_ON(IS_CLUS_EOF(clu
.dir
) || IS_CLUS_FREE(clu
.dir
));
338 if (get_next_clus_safe(inode
->i_sb
, &(clu
.dir
)))
339 EMSG("%s: failed to access to FAT\n");
344 BUG_ON(!IS_CLUS_EOF(clu
.dir
));
347 #endif /* CONFIG_SDFAT_DBG_CAREFUL */
349 #ifdef CONFIG_SDFAT_DBG_MSG
350 void __sdfat_dmsg(int level
, const char *fmt
, ...)
352 #ifdef CONFIG_SDFAT_DBG_SHOW_PID
353 struct va_format vaf
;
356 /* should check type */
357 if (level
> SDFAT_MSG_LEVEL
)
363 /* fmt already includes KERN_ pacility level */
364 printk("[%u] %pV", current
->pid
, &vaf
);
369 /* should check type */
370 if (level
> SDFAT_MSG_LEVEL
)
374 /* fmt already includes KERN_ pacility level */