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