Import 2.3.7pre7
[davej-history.git] / fs / ext2 / fsync.c
blobb6dd9bce6cda35b3aa28e1b32adab63ad7fafa3d
1 /*
2 * linux/fs/ext2/fsync.c
4 * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk)
5 * from
6 * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
7 * Laboratoire MASI - Institut Blaise Pascal
8 * Universite Pierre et Marie Curie (Paris VI)
9 * from
10 * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
12 * ext2fs fsync primitive
14 * Big-endian to little-endian byte-swapping/bitmaps by
15 * David S. Miller (davem@caip.rutgers.edu), 1995
17 * Removed unnecessary code duplication for little endian machines
18 * and excessive __inline__s.
19 * Andi Kleen, 1997
22 #include <asm/uaccess.h>
23 #include <asm/system.h>
24 #include <asm/byteorder.h>
26 #include <linux/errno.h>
27 #include <linux/fs.h>
28 #include <linux/ext2_fs.h>
29 #include <linux/fcntl.h>
30 #include <linux/sched.h>
31 #include <linux/stat.h>
32 #include <linux/locks.h>
35 #define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
36 #define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
38 static int sync_indirect(struct inode * inode, u32 * block, int wait)
40 struct buffer_head * bh;
42 if (!*block)
43 return 0;
44 bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), blocksize);
45 if (!bh)
46 return 0;
47 if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
48 brelse (bh);
49 return -1;
51 if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
52 brelse (bh);
53 return 0;
55 ll_rw_block (WRITE, 1, &bh);
56 bh->b_count--;
57 return 0;
60 static int sync_iblock (struct inode * inode, u32 * iblock,
61 struct buffer_head ** bh, int wait)
63 int rc, tmp;
65 *bh = NULL;
66 tmp = le32_to_cpu(*iblock);
67 if (!tmp)
68 return 0;
69 rc = sync_indirect(inode, iblock, wait);
70 if (rc)
71 return rc;
72 *bh = bread (inode->i_dev, tmp, blocksize);
73 if (!*bh)
74 return -1;
75 return 0;
78 static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
80 int i;
81 struct buffer_head * dind_bh;
82 int rc, err = 0;
84 rc = sync_iblock (inode, diblock, &dind_bh, wait);
85 if (rc || !dind_bh)
86 return rc;
88 for (i = 0; i < addr_per_block; i++) {
89 rc = sync_indirect(inode,
90 ((u32 *) dind_bh->b_data) + i,
91 wait);
92 if (rc)
93 err = rc;
95 brelse (dind_bh);
96 return err;
99 static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
101 int i;
102 struct buffer_head * tind_bh;
103 int rc, err = 0;
105 rc = sync_iblock (inode, tiblock, &tind_bh, wait);
106 if (rc || !tind_bh)
107 return rc;
109 for (i = 0; i < addr_per_block; i++) {
110 rc = sync_dindirect(inode,
111 ((u32 *) tind_bh->b_data) + i,
112 wait);
113 if (rc)
114 err = rc;
116 brelse (tind_bh);
117 return err;
121 * File may be NULL when we are called. Perhaps we shouldn't
122 * even pass file to fsync ?
125 int ext2_sync_file(struct file * file, struct dentry *dentry)
127 int wait, err = 0;
128 struct inode *inode = dentry->d_inode;
130 if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
132 * Don't sync fast links!
134 goto skip;
136 err = generic_buffer_fdatasync(inode, 0, ~0UL);
138 for (wait=0; wait<=1; wait++)
140 err |= sync_indirect (inode,
141 inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
142 wait);
143 err |= sync_dindirect (inode,
144 inode->u.ext2_i.i_data+EXT2_DIND_BLOCK,
145 wait);
146 err |= sync_tindirect (inode,
147 inode->u.ext2_i.i_data+EXT2_TIND_BLOCK,
148 wait);
150 skip:
151 err |= ext2_sync_inode (inode);
152 return err ? -EIO : 0;