diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/audit_tree.c | 19 | ||||
-rw-r--r-- | kernel/task_work.c | 1 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 37 |
3 files changed, 45 insertions, 12 deletions
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 3a5ca582ba1e..ed206fd88cca 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c | |||
@@ -250,7 +250,6 @@ static void untag_chunk(struct node *p) | |||
250 | spin_unlock(&hash_lock); | 250 | spin_unlock(&hash_lock); |
251 | spin_unlock(&entry->lock); | 251 | spin_unlock(&entry->lock); |
252 | fsnotify_destroy_mark(entry); | 252 | fsnotify_destroy_mark(entry); |
253 | fsnotify_put_mark(entry); | ||
254 | goto out; | 253 | goto out; |
255 | } | 254 | } |
256 | 255 | ||
@@ -259,7 +258,7 @@ static void untag_chunk(struct node *p) | |||
259 | 258 | ||
260 | fsnotify_duplicate_mark(&new->mark, entry); | 259 | fsnotify_duplicate_mark(&new->mark, entry); |
261 | if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) { | 260 | if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) { |
262 | free_chunk(new); | 261 | fsnotify_put_mark(&new->mark); |
263 | goto Fallback; | 262 | goto Fallback; |
264 | } | 263 | } |
265 | 264 | ||
@@ -293,7 +292,7 @@ static void untag_chunk(struct node *p) | |||
293 | spin_unlock(&hash_lock); | 292 | spin_unlock(&hash_lock); |
294 | spin_unlock(&entry->lock); | 293 | spin_unlock(&entry->lock); |
295 | fsnotify_destroy_mark(entry); | 294 | fsnotify_destroy_mark(entry); |
296 | fsnotify_put_mark(entry); | 295 | fsnotify_put_mark(&new->mark); /* drop initial reference */ |
297 | goto out; | 296 | goto out; |
298 | 297 | ||
299 | Fallback: | 298 | Fallback: |
@@ -322,7 +321,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree) | |||
322 | 321 | ||
323 | entry = &chunk->mark; | 322 | entry = &chunk->mark; |
324 | if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 0)) { | 323 | if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 0)) { |
325 | free_chunk(chunk); | 324 | fsnotify_put_mark(entry); |
326 | return -ENOSPC; | 325 | return -ENOSPC; |
327 | } | 326 | } |
328 | 327 | ||
@@ -347,6 +346,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree) | |||
347 | insert_hash(chunk); | 346 | insert_hash(chunk); |
348 | spin_unlock(&hash_lock); | 347 | spin_unlock(&hash_lock); |
349 | spin_unlock(&entry->lock); | 348 | spin_unlock(&entry->lock); |
349 | fsnotify_put_mark(entry); /* drop initial reference */ | ||
350 | return 0; | 350 | return 0; |
351 | } | 351 | } |
352 | 352 | ||
@@ -396,7 +396,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) | |||
396 | fsnotify_duplicate_mark(chunk_entry, old_entry); | 396 | fsnotify_duplicate_mark(chunk_entry, old_entry); |
397 | if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, NULL, 1)) { | 397 | if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, NULL, 1)) { |
398 | spin_unlock(&old_entry->lock); | 398 | spin_unlock(&old_entry->lock); |
399 | free_chunk(chunk); | 399 | fsnotify_put_mark(chunk_entry); |
400 | fsnotify_put_mark(old_entry); | 400 | fsnotify_put_mark(old_entry); |
401 | return -ENOSPC; | 401 | return -ENOSPC; |
402 | } | 402 | } |
@@ -444,8 +444,8 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) | |||
444 | spin_unlock(&chunk_entry->lock); | 444 | spin_unlock(&chunk_entry->lock); |
445 | spin_unlock(&old_entry->lock); | 445 | spin_unlock(&old_entry->lock); |
446 | fsnotify_destroy_mark(old_entry); | 446 | fsnotify_destroy_mark(old_entry); |
447 | fsnotify_put_mark(chunk_entry); /* drop initial reference */ | ||
447 | fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ | 448 | fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ |
448 | fsnotify_put_mark(old_entry); /* and kill it */ | ||
449 | return 0; | 449 | return 0; |
450 | } | 450 | } |
451 | 451 | ||
@@ -916,7 +916,12 @@ static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify | |||
916 | struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark); | 916 | struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark); |
917 | 917 | ||
918 | evict_chunk(chunk); | 918 | evict_chunk(chunk); |
919 | fsnotify_put_mark(entry); | 919 | |
920 | /* | ||
921 | * We are guaranteed to have at least one reference to the mark from | ||
922 | * either the inode or the caller of fsnotify_destroy_mark(). | ||
923 | */ | ||
924 | BUG_ON(atomic_read(&entry->refcnt) < 1); | ||
920 | } | 925 | } |
921 | 926 | ||
922 | static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode, | 927 | static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode, |
diff --git a/kernel/task_work.c b/kernel/task_work.c index 91d4e1742a0c..d320d44903bd 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c | |||
@@ -75,6 +75,7 @@ void task_work_run(void) | |||
75 | p = q->next; | 75 | p = q->next; |
76 | q->func(q); | 76 | q->func(q); |
77 | q = p; | 77 | q = p; |
78 | cond_resched(); | ||
78 | } | 79 | } |
79 | } | 80 | } |
80 | } | 81 | } |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index e16af197a2bc..0c1485e42be6 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -115,6 +115,7 @@ static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts) | |||
115 | { | 115 | { |
116 | tk->xtime_sec += ts->tv_sec; | 116 | tk->xtime_sec += ts->tv_sec; |
117 | tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift; | 117 | tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift; |
118 | tk_normalize_xtime(tk); | ||
118 | } | 119 | } |
119 | 120 | ||
120 | static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) | 121 | static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) |
@@ -276,7 +277,7 @@ static void timekeeping_forward_now(struct timekeeper *tk) | |||
276 | tk->xtime_nsec += cycle_delta * tk->mult; | 277 | tk->xtime_nsec += cycle_delta * tk->mult; |
277 | 278 | ||
278 | /* If arch requires, add in gettimeoffset() */ | 279 | /* If arch requires, add in gettimeoffset() */ |
279 | tk->xtime_nsec += arch_gettimeoffset() << tk->shift; | 280 | tk->xtime_nsec += (u64)arch_gettimeoffset() << tk->shift; |
280 | 281 | ||
281 | tk_normalize_xtime(tk); | 282 | tk_normalize_xtime(tk); |
282 | 283 | ||
@@ -427,7 +428,7 @@ int do_settimeofday(const struct timespec *tv) | |||
427 | struct timespec ts_delta, xt; | 428 | struct timespec ts_delta, xt; |
428 | unsigned long flags; | 429 | unsigned long flags; |
429 | 430 | ||
430 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | 431 | if (!timespec_valid(tv)) |
431 | return -EINVAL; | 432 | return -EINVAL; |
432 | 433 | ||
433 | write_seqlock_irqsave(&tk->lock, flags); | 434 | write_seqlock_irqsave(&tk->lock, flags); |
@@ -463,6 +464,8 @@ int timekeeping_inject_offset(struct timespec *ts) | |||
463 | { | 464 | { |
464 | struct timekeeper *tk = &timekeeper; | 465 | struct timekeeper *tk = &timekeeper; |
465 | unsigned long flags; | 466 | unsigned long flags; |
467 | struct timespec tmp; | ||
468 | int ret = 0; | ||
466 | 469 | ||
467 | if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) | 470 | if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) |
468 | return -EINVAL; | 471 | return -EINVAL; |
@@ -471,10 +474,17 @@ int timekeeping_inject_offset(struct timespec *ts) | |||
471 | 474 | ||
472 | timekeeping_forward_now(tk); | 475 | timekeeping_forward_now(tk); |
473 | 476 | ||
477 | /* Make sure the proposed value is valid */ | ||
478 | tmp = timespec_add(tk_xtime(tk), *ts); | ||
479 | if (!timespec_valid(&tmp)) { | ||
480 | ret = -EINVAL; | ||
481 | goto error; | ||
482 | } | ||
474 | 483 | ||
475 | tk_xtime_add(tk, ts); | 484 | tk_xtime_add(tk, ts); |
476 | tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); | 485 | tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); |
477 | 486 | ||
487 | error: /* even if we error out, we forwarded the time, so call update */ | ||
478 | timekeeping_update(tk, true); | 488 | timekeeping_update(tk, true); |
479 | 489 | ||
480 | write_sequnlock_irqrestore(&tk->lock, flags); | 490 | write_sequnlock_irqrestore(&tk->lock, flags); |
@@ -482,7 +492,7 @@ int timekeeping_inject_offset(struct timespec *ts) | |||
482 | /* signal hrtimers about time change */ | 492 | /* signal hrtimers about time change */ |
483 | clock_was_set(); | 493 | clock_was_set(); |
484 | 494 | ||
485 | return 0; | 495 | return ret; |
486 | } | 496 | } |
487 | EXPORT_SYMBOL(timekeeping_inject_offset); | 497 | EXPORT_SYMBOL(timekeeping_inject_offset); |
488 | 498 | ||
@@ -649,7 +659,20 @@ void __init timekeeping_init(void) | |||
649 | struct timespec now, boot, tmp; | 659 | struct timespec now, boot, tmp; |
650 | 660 | ||
651 | read_persistent_clock(&now); | 661 | read_persistent_clock(&now); |
662 | if (!timespec_valid(&now)) { | ||
663 | pr_warn("WARNING: Persistent clock returned invalid value!\n" | ||
664 | " Check your CMOS/BIOS settings.\n"); | ||
665 | now.tv_sec = 0; | ||
666 | now.tv_nsec = 0; | ||
667 | } | ||
668 | |||
652 | read_boot_clock(&boot); | 669 | read_boot_clock(&boot); |
670 | if (!timespec_valid(&boot)) { | ||
671 | pr_warn("WARNING: Boot clock returned invalid value!\n" | ||
672 | " Check your CMOS/BIOS settings.\n"); | ||
673 | boot.tv_sec = 0; | ||
674 | boot.tv_nsec = 0; | ||
675 | } | ||
653 | 676 | ||
654 | seqlock_init(&tk->lock); | 677 | seqlock_init(&tk->lock); |
655 | 678 | ||
@@ -1129,6 +1152,10 @@ static void update_wall_time(void) | |||
1129 | offset = (clock->read(clock) - clock->cycle_last) & clock->mask; | 1152 | offset = (clock->read(clock) - clock->cycle_last) & clock->mask; |
1130 | #endif | 1153 | #endif |
1131 | 1154 | ||
1155 | /* Check if there's really nothing to do */ | ||
1156 | if (offset < tk->cycle_interval) | ||
1157 | goto out; | ||
1158 | |||
1132 | /* | 1159 | /* |
1133 | * With NO_HZ we may have to accumulate many cycle_intervals | 1160 | * With NO_HZ we may have to accumulate many cycle_intervals |
1134 | * (think "ticks") worth of time at once. To do this efficiently, | 1161 | * (think "ticks") worth of time at once. To do this efficiently, |
@@ -1161,9 +1188,9 @@ static void update_wall_time(void) | |||
1161 | * the vsyscall implementations are converted to use xtime_nsec | 1188 | * the vsyscall implementations are converted to use xtime_nsec |
1162 | * (shifted nanoseconds), this can be killed. | 1189 | * (shifted nanoseconds), this can be killed. |
1163 | */ | 1190 | */ |
1164 | remainder = tk->xtime_nsec & ((1 << tk->shift) - 1); | 1191 | remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); |
1165 | tk->xtime_nsec -= remainder; | 1192 | tk->xtime_nsec -= remainder; |
1166 | tk->xtime_nsec += 1 << tk->shift; | 1193 | tk->xtime_nsec += 1ULL << tk->shift; |
1167 | tk->ntp_error += remainder << tk->ntp_error_shift; | 1194 | tk->ntp_error += remainder << tk->ntp_error_shift; |
1168 | 1195 | ||
1169 | /* | 1196 | /* |