import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / qnx4 / fsync.c
1 /* 
2  * QNX4 file system, Linux implementation.
3  * 
4  * Version : 0.1
5  * 
6  * Using parts of the xiafs filesystem.
7  * 
8  * History :
9  * 
10  * 24-03-1998 by Richard Frowijn : first release.
11  */
12
13 #include <linux/config.h>
14 #include <linux/errno.h>
15 #include <linux/sched.h>
16 #include <linux/stat.h>
17 #include <linux/fcntl.h>
18 #include <linux/locks.h>
19 #include <linux/smp_lock.h>
20
21 #include <linux/fs.h>
22 #include <linux/qnx4_fs.h>
23
24 #include <asm/segment.h>
25 #include <asm/system.h>
26
27 /*
28  * The functions for qnx4 fs file synchronization.
29  */
30
31 #ifdef CONFIG_QNX4FS_RW
32
33 static int sync_block(struct inode *inode, unsigned short *block, int wait)
34 {
35         struct buffer_head *bh;
36         unsigned short tmp;
37
38         if (!*block)
39                 return 0;
40         tmp = *block;
41         bh = sb_get_hash_table(inode->i_sb, *block);
42         if (!bh)
43                 return 0;
44         if (*block != tmp) {
45                 brelse(bh);
46                 return 1;
47         }
48         if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
49                 brelse(bh);
50                 return -1;
51         }
52         if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
53                 brelse(bh);
54                 return 0;
55         }
56         ll_rw_block(WRITE, 1, &bh);
57         atomic_dec(&bh->b_count);
58         return 0;
59 }
60
61 #ifdef WTF
62 static int sync_iblock(struct inode *inode, unsigned short *iblock,
63                        struct buffer_head **bh, int wait)
64 {
65         int rc;
66         unsigned short tmp;
67
68         *bh = NULL;
69         tmp = *iblock;
70         if (!tmp)
71                 return 0;
72         rc = sync_block(inode, iblock, wait);
73         if (rc)
74                 return rc;
75         *bh = sb_bread(inode->i_sb, tmp);
76         if (tmp != *iblock) {
77                 brelse(*bh);
78                 *bh = NULL;
79                 return 1;
80         }
81         if (!*bh)
82                 return -1;
83         return 0;
84 }
85 #endif
86
87 static int sync_direct(struct inode *inode, int wait)
88 {
89         int i;
90         int rc, err = 0;
91
92         for (i = 0; i < 7; i++) {
93                 rc = sync_block(inode,
94                                 (unsigned short *) inode->u.qnx4_i.i_first_xtnt.xtnt_blk + i, wait);
95                 if (rc > 0)
96                         break;
97                 if (rc)
98                         err = rc;
99         }
100         return err;
101 }
102
103 #ifdef WTF
104 static int sync_indirect(struct inode *inode, unsigned short *iblock, int wait)
105 {
106         int i;
107         struct buffer_head *ind_bh;
108         int rc, err = 0;
109
110         rc = sync_iblock(inode, iblock, &ind_bh, wait);
111         if (rc || !ind_bh)
112                 return rc;
113
114         for (i = 0; i < 512; i++) {
115                 rc = sync_block(inode,
116                                 ((unsigned short *) ind_bh->b_data) + i,
117                                 wait);
118                 if (rc > 0)
119                         break;
120                 if (rc)
121                         err = rc;
122         }
123         brelse(ind_bh);
124         return err;
125 }
126
127 static int sync_dindirect(struct inode *inode, unsigned short *diblock,
128                           int wait)
129 {
130         int i;
131         struct buffer_head *dind_bh;
132         int rc, err = 0;
133
134         rc = sync_iblock(inode, diblock, &dind_bh, wait);
135         if (rc || !dind_bh)
136                 return rc;
137
138         for (i = 0; i < 512; i++) {
139                 rc = sync_indirect(inode,
140                                 ((unsigned short *) dind_bh->b_data) + i,
141                                    wait);
142                 if (rc > 0)
143                         break;
144                 if (rc)
145                         err = rc;
146         }
147         brelse(dind_bh);
148         return err;
149 }
150 #endif
151
152 int qnx4_sync_file(struct file *file, struct dentry *dentry, int unused)
153 {
154         struct inode *inode = dentry->d_inode;
155         int wait, err = 0;
156         
157         (void) file;
158         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
159               S_ISLNK(inode->i_mode)))
160                 return -EINVAL;
161
162         lock_kernel();
163         for (wait = 0; wait <= 1; wait++) {
164                 err |= sync_direct(inode, wait);
165         }
166         err |= qnx4_sync_inode(inode);
167         unlock_kernel();
168         return (err < 0) ? -EIO : 0;
169 }
170
171 #endif