1/*
2 * ntfs_usnjrnl.c - NTFS kernel transaction log ($UsnJrnl) handling.
3 *
4 * Copyright (c) 2006-2011 Anton Altaparmakov.  All Rights Reserved.
5 * Portions Copyright (c) 2006-2011 Apple Inc.  All Rights Reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 *    this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 *    this list of conditions and the following disclaimer in the documentation
14 *    and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its
16 *    contributors may be used to endorse or promote products derived from this
17 *    software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * ALTERNATIVELY, provided that this notice and licensing terms are retained in
31 * full, this file may be redistributed and/or modified under the terms of the
32 * GNU General Public License (GPL) Version 2, in which case the provisions of
33 * that version of the GPL will apply to you instead of the license terms
34 * above.  You can obtain a copy of the GPL Version 2 at
35 * http://developer.apple.com/opensource/licenses/gpl-2.txt.
36 */
37
38#include <sys/errno.h>
39
40#include <kern/locks.h>
41
42#include "ntfs_debug.h"
43#include "ntfs_endian.h"
44#include "ntfs_page.h"
45#include "ntfs_time.h"
46#include "ntfs_types.h"
47#include "ntfs_usnjrnl.h"
48#include "ntfs_volume.h"
49
50/**
51 * ntfs_usnjrnl_stamp - stamp the transaction log ($UsnJrnl) on an ntfs volume
52 * @vol:	ntfs volume on which to stamp the transaction log
53 *
54 * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return 0
55 * on success and errno on error.
56 *
57 * This function assumes that the transaction log has already been loaded and
58 * consistency checked by a call to ntfs_vfsops.c::ntfs_usnjrnl_load().
59 */
60errno_t ntfs_usnjrnl_stamp(ntfs_volume *vol)
61{
62	ntfs_debug("Entering.");
63	if (!NVolUsnJrnlStamped(vol)) {
64		sle64 j_size, stamp;
65		upl_t upl;
66		upl_page_info_array_t pl;
67		USN_HEADER *uh;
68		ntfs_inode *max_ni;
69		errno_t err;
70
71		lck_spin_lock(&vol->usnjrnl_j_ni->size_lock);
72		j_size = vol->usnjrnl_j_ni->data_size;
73		lck_spin_unlock(&vol->usnjrnl_j_ni->size_lock);
74		max_ni = vol->usnjrnl_max_ni;
75		err = vnode_get(max_ni->vn);
76		if (err) {
77			ntfs_error(vol->mp, "Failed to get vnode for "
78					"$UsnJrnl/$DATA/$Max.");
79			return err;
80		}
81		lck_rw_lock_shared(&max_ni->lock);
82		err = ntfs_page_map(max_ni, 0, &upl, &pl, (u8**)&uh, TRUE);
83		if (err) {
84			ntfs_error(vol->mp, "Failed to read from "
85					"$UsnJrnl/$DATA/$Max attribute.");
86			(void)vnode_put(max_ni->vn);
87			return err;
88		}
89		stamp = ntfs_current_time();
90		ntfs_debug("Stamping transaction log ($UsnJrnl): old "
91				"journal_id 0x%llx, old lowest_valid_usn "
92				"0x%llx, new journal_id 0x%llx, new "
93				"lowest_valid_usn 0x%llx.",
94				(unsigned long long)
95				sle64_to_cpu(uh->journal_id),
96				(unsigned long long)
97				sle64_to_cpu(uh->lowest_valid_usn),
98				(unsigned long long)sle64_to_cpu(stamp),
99				(unsigned long long)j_size);
100		uh->lowest_valid_usn = cpu_to_sle64(j_size);
101		uh->journal_id = stamp;
102		ntfs_page_unmap(max_ni, upl, pl, TRUE);
103		lck_rw_unlock_shared(&max_ni->lock);
104		(void)vnode_put(max_ni->vn);
105		/* Set the flag so we do not have to do it again on remount. */
106		NVolSetUsnJrnlStamped(vol);
107		// TODO: Should we mark any times on the base inode $UsnJrnl
108		// for update here?
109	}
110	ntfs_debug("Done.");
111	return 0;
112}
113