int (* fs_sync)(struct super_block *sb);
int (* fs_prep_san_write)(struct inode *inode, long *blocks,
int nblocks, loff_t newsize);
+ int (* fs_write_record)(struct file *, char *, loff_t, loff_t *);
+ int (* fs_read_record)(struct file *, char *, loff_t, loff_t *);
};
extern int fsfilt_register_ops(struct fsfilt_operations *fs_ops);
return obd->obd_fsops->fs_prep_san_write(inode, blocks,
nblocks, newsize);
}
+
+static inline int fsfilt_read_record(struct obd_device *obd, struct file *file,
+ char *buf, loff_t size, loff_t *offs)
+{
+ return obd->obd_fsops->fs_read_record(file, buf, size, offs);
+}
+
+static inline int fsfilt_write_record(struct obd_device *obd, struct file *file,
+ char *buf, loff_t size, loff_t *offs)
+{
+ return obd->obd_fsops->fs_write_record(file, buf, size, offs);
+}
+
#endif /* __KERNEL__ */
#endif
return ext3_prep_san_write(inode, blocks, nblocks, newsize);
}
+static int fsfilt_ext3_read_record(struct file * file, char * buf,
+ loff_t size, loff_t *offs)
+{
+ struct buffer_head *bh;
+ unsigned long block, boffs;
+ struct inode *inode = file->f_dentry->d_inode;
+ int err;
+
+ if (inode->i_size < *offs + size)
+ return -EIO;
+
+ block = *offs >> inode->i_blkbits;
+ bh = ext3_bread(NULL, inode, block, 0, &err);
+ if (!bh)
+ return err;
+
+ boffs = (unsigned) *offs / bh->b_size;
+ if (boffs + size > bh->b_size) {
+ brelse(bh);
+ return -EIO;
+ }
+
+ memcpy(buf, bh->b_data + boffs, size);
+ brelse(bh);
+ *offs += size;
+ return size;
+}
+
+static int fsfilt_ext3_write_record(struct file * file, char * buf,
+ loff_t size, loff_t *offs)
+{
+ struct buffer_head *bh;
+ unsigned long block, boffs;
+ struct inode *inode = file->f_dentry->d_inode;
+ handle_t *handle;
+ int err;
+
+ handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS + 2);
+ if (!handle)
+ return -EIO;
+
+ block = *offs >> inode->i_blkbits;
+ if (block > inode->i_size >> inode->i_blkbits) {
+ down(&inode->i_sem);
+ inode->i_size = block << inode->i_blkbits;
+ up(&inode->i_sem);
+ }
+ bh = ext3_bread(handle, inode, block, 1, &err);
+ if (!bh)
+ goto out;
+
+ boffs = (unsigned) *offs / bh->b_size;
+ if (boffs + size > bh->b_size)
+ goto out;
+
+ err = ext3_journal_get_write_access(handle, bh);
+ if (err)
+ goto out;
+ memcpy(bh->b_data + boffs, buf, size);
+ err = ext3_journal_dirty_metadata(handle, bh);
+ if (err)
+ goto out;
+ err = size;
+out:
+ if (bh)
+ brelse(bh);
+ ext3_journal_stop(handle, inode);
+ if (err > 0)
+ *offs += size;
+ return err;
+}
+
static struct fsfilt_operations fsfilt_ext3_ops = {
fs_type: "ext3",
fs_owner: THIS_MODULE,
fs_statfs: fsfilt_ext3_statfs,
fs_sync: fsfilt_ext3_sync,
fs_prep_san_write: fsfilt_ext3_prep_san_write,
+ fs_write_record: fsfilt_ext3_write_record,
+ fs_read_record: fsfilt_ext3_read_record,
};
static int __init fsfilt_ext3_init(void)