|  | /* | 
|  | * QNX4 file system, Linux implementation. | 
|  | * | 
|  | * Version : 0.1 | 
|  | * | 
|  | * Using parts of the xiafs filesystem. | 
|  | * | 
|  | * History : | 
|  | * | 
|  | * 24-03-1998 by Richard Frowijn : first release. | 
|  | */ | 
|  |  | 
|  | #include <linux/errno.h> | 
|  | #include <linux/time.h> | 
|  | #include <linux/stat.h> | 
|  | #include <linux/fcntl.h> | 
|  | #include <linux/smp_lock.h> | 
|  | #include <linux/buffer_head.h> | 
|  |  | 
|  | #include <linux/fs.h> | 
|  | #include <linux/qnx4_fs.h> | 
|  |  | 
|  | #include <asm/system.h> | 
|  |  | 
|  | /* | 
|  | * The functions for qnx4 fs file synchronization. | 
|  | */ | 
|  |  | 
|  | #ifdef CONFIG_QNX4FS_RW | 
|  |  | 
|  | static int sync_block(struct inode *inode, unsigned short *block, int wait) | 
|  | { | 
|  | struct buffer_head *bh; | 
|  | unsigned short tmp; | 
|  |  | 
|  | if (!*block) | 
|  | return 0; | 
|  | tmp = *block; | 
|  | bh = sb_find_get_block(inode->i_sb, *block); | 
|  | if (!bh) | 
|  | return 0; | 
|  | if (*block != tmp) { | 
|  | brelse(bh); | 
|  | return 1; | 
|  | } | 
|  | if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { | 
|  | brelse(bh); | 
|  | return -1; | 
|  | } | 
|  | if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) { | 
|  | brelse(bh); | 
|  | return 0; | 
|  | } | 
|  | ll_rw_block(WRITE, 1, &bh); | 
|  | atomic_dec(&bh->b_count); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #ifdef WTF | 
|  | static int sync_iblock(struct inode *inode, unsigned short *iblock, | 
|  | struct buffer_head **bh, int wait) | 
|  | { | 
|  | int rc; | 
|  | unsigned short tmp; | 
|  |  | 
|  | *bh = NULL; | 
|  | tmp = *iblock; | 
|  | if (!tmp) | 
|  | return 0; | 
|  | rc = sync_block(inode, iblock, wait); | 
|  | if (rc) | 
|  | return rc; | 
|  | *bh = sb_bread(inode->i_sb, tmp); | 
|  | if (tmp != *iblock) { | 
|  | brelse(*bh); | 
|  | *bh = NULL; | 
|  | return 1; | 
|  | } | 
|  | if (!*bh) | 
|  | return -1; | 
|  | return 0; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static int sync_direct(struct inode *inode, int wait) | 
|  | { | 
|  | int i; | 
|  | int rc, err = 0; | 
|  |  | 
|  | for (i = 0; i < 7; i++) { | 
|  | rc = sync_block(inode, | 
|  | (unsigned short *) qnx4_raw_inode(inode)->di_first_xtnt.xtnt_blk + i, wait); | 
|  | if (rc > 0) | 
|  | break; | 
|  | if (rc) | 
|  | err = rc; | 
|  | } | 
|  | return err; | 
|  | } | 
|  |  | 
|  | #ifdef WTF | 
|  | static int sync_indirect(struct inode *inode, unsigned short *iblock, int wait) | 
|  | { | 
|  | int i; | 
|  | struct buffer_head *ind_bh; | 
|  | int rc, err = 0; | 
|  |  | 
|  | rc = sync_iblock(inode, iblock, &ind_bh, wait); | 
|  | if (rc || !ind_bh) | 
|  | return rc; | 
|  |  | 
|  | for (i = 0; i < 512; i++) { | 
|  | rc = sync_block(inode, | 
|  | ((unsigned short *) ind_bh->b_data) + i, | 
|  | wait); | 
|  | if (rc > 0) | 
|  | break; | 
|  | if (rc) | 
|  | err = rc; | 
|  | } | 
|  | brelse(ind_bh); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | static int sync_dindirect(struct inode *inode, unsigned short *diblock, | 
|  | int wait) | 
|  | { | 
|  | int i; | 
|  | struct buffer_head *dind_bh; | 
|  | int rc, err = 0; | 
|  |  | 
|  | rc = sync_iblock(inode, diblock, &dind_bh, wait); | 
|  | if (rc || !dind_bh) | 
|  | return rc; | 
|  |  | 
|  | for (i = 0; i < 512; i++) { | 
|  | rc = sync_indirect(inode, | 
|  | ((unsigned short *) dind_bh->b_data) + i, | 
|  | wait); | 
|  | if (rc > 0) | 
|  | break; | 
|  | if (rc) | 
|  | err = rc; | 
|  | } | 
|  | brelse(dind_bh); | 
|  | return err; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | int qnx4_sync_file(struct file *file, struct dentry *dentry, int unused) | 
|  | { | 
|  | struct inode *inode = dentry->d_inode; | 
|  | int wait, err = 0; | 
|  |  | 
|  | (void) file; | 
|  | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 
|  | S_ISLNK(inode->i_mode))) | 
|  | return -EINVAL; | 
|  |  | 
|  | lock_kernel(); | 
|  | for (wait = 0; wait <= 1; wait++) { | 
|  | err |= sync_direct(inode, wait); | 
|  | } | 
|  | err |= qnx4_sync_inode(inode); | 
|  | unlock_kernel(); | 
|  | return (err < 0) ? -EIO : 0; | 
|  | } | 
|  |  | 
|  | #endif |