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