-static int fsfilt_ext3_commit_async(struct inode *inode, void *h,
- void **wait_handle)
-{
- unsigned long tid;
- transaction_t *transaction;
- handle_t *handle = h;
- journal_t *journal;
- int rc;
-
- LASSERT(current->journal_info == handle);
-
- transaction = handle->h_transaction;
- journal = transaction->t_journal;
- tid = transaction->t_tid;
- /* we don't want to be blocked */
- handle->h_sync = 0;
- rc = ext3_journal_stop(handle);
- if (rc) {
- CERROR("error while stopping transaction: %d\n", rc);
- return rc;
- }
- fsfilt_log_start_commit(journal, tid);
-
- *wait_handle = (void *) tid;
- CDEBUG(D_INODE, "commit async: %lu\n", (unsigned long) tid);
- return 0;
-}
-
-static int fsfilt_ext3_commit_wait(struct inode *inode, void *h)
-{
- journal_t *journal = EXT3_JOURNAL(inode);
- tid_t tid = (tid_t)(long)h;
-
- CDEBUG(D_INODE, "commit wait: %lu\n", (unsigned long) tid);
- if (unlikely(is_journal_aborted(journal)))
- return -EIO;
-
- fsfilt_log_wait_commit(EXT3_JOURNAL(inode), tid);
-
- if (unlikely(is_journal_aborted(journal)))
- return -EIO;
- return 0;
-}
-
-static int fsfilt_ext3_setattr(struct dentry *dentry, void *handle,
- struct iattr *iattr, int do_trunc)
-{
- struct inode *inode = dentry->d_inode;
- int rc = 0;
-
-#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 7, 50, 0)
- /* Try to correct for a bug in 2.1.0 (LU-221) that caused negative
- * timestamps to appear to be in the far future, due old timestamp
- * being stored on disk as an unsigned value. This fixes up any
- * bad values held by the client before storing them on disk,
- * and ensures any timestamp updates are correct. LU-1042 */
- if (unlikely(LTIME_S(inode->i_atime) == LU221_BAD_TIME &&
- !(iattr->ia_valid & ATTR_ATIME))) {
- iattr->ia_valid |= ATTR_ATIME;
- LTIME_S(iattr->ia_atime) = 0;
- }
- if (unlikely(LTIME_S(inode->i_mtime) == LU221_BAD_TIME &&
- !(iattr->ia_valid & ATTR_MTIME))) {
- iattr->ia_valid |= ATTR_MTIME;
- LTIME_S(iattr->ia_mtime) = 0;
- }
- if (unlikely((LTIME_S(inode->i_ctime) == LU221_BAD_TIME ||
- LTIME_S(inode->i_ctime) == 0) &&
- !(iattr->ia_valid & ATTR_CTIME))) {
- iattr->ia_valid |= ATTR_CTIME;
- LTIME_S(iattr->ia_ctime) = 0;
- }
-#else
-#warning "remove old LU-221/LU-1042 workaround code"
-#endif
-
- /* When initializating timestamps for new inodes, use the filesystem
- * mkfs time for ctime to avoid e2fsck ibadness incorrectly thinking
- * that this is potentially an invalid inode. Files with an old ctime
- * migrated to a newly-formatted OST with a newer s_mkfs_time will not
- * hit this check, since it is only for ctime == 0. LU-1010/LU-1042 */
- if ((iattr->ia_valid & ATTR_CTIME) && LTIME_S(iattr->ia_ctime) == 0)
- LTIME_S(iattr->ia_ctime) =
- EXT4_SB(inode->i_sb)->s_es->s_mkfs_time;
-
- /* Avoid marking the inode dirty on the superblock list unnecessarily.
- * We are already writing the inode to disk as part of this
- * transaction and want to avoid a lot of extra inode writeout
- * later on. b=9828 */
- if (iattr->ia_valid & ATTR_SIZE && !do_trunc) {
- /* ATTR_SIZE would invoke truncate: clear it */
- iattr->ia_valid &= ~ATTR_SIZE;
- EXT3_I(inode)->i_disksize = iattr->ia_size;
- i_size_write(inode, iattr->ia_size);
-
- if (iattr->ia_valid & ATTR_UID)
- inode->i_uid = iattr->ia_uid;
- if (iattr->ia_valid & ATTR_GID)
- inode->i_gid = iattr->ia_gid;
- if (iattr->ia_valid & ATTR_ATIME)
- inode->i_atime = iattr->ia_atime;
- if (iattr->ia_valid & ATTR_MTIME)
- inode->i_mtime = iattr->ia_mtime;
- if (iattr->ia_valid & ATTR_CTIME)
- inode->i_ctime = iattr->ia_ctime;
- if (iattr->ia_valid & ATTR_MODE) {
- inode->i_mode = iattr->ia_mode;
-
- if (!cfs_curproc_is_in_groups(inode->i_gid) &&
- !cfs_capable(CFS_CAP_FSETID))
- inode->i_mode &= ~S_ISGID;
- }
-
- inode->i_sb->s_op->dirty_inode(inode);
-
- goto out;
- }
-
- /* Don't allow setattr to change file type */
- if (iattr->ia_valid & ATTR_MODE)
- iattr->ia_mode = (inode->i_mode & S_IFMT) |
- (iattr->ia_mode & ~S_IFMT);
-
- /* We set these flags on the client, but have already checked perms
- * so don't confuse inode_change_ok. */
- iattr->ia_valid &= ~TIMES_SET_FLAGS;
-
- if (inode->i_op->setattr) {
- rc = inode->i_op->setattr(dentry, iattr);
- } else {
-#ifndef HAVE_SIMPLE_SETATTR /* simple_setattr() already call it */
- rc = inode_change_ok(inode, iattr);
- if (!rc)
-#endif
- rc = simple_setattr(dentry, iattr);
- }
-
- out:
- RETURN(rc);
-}
-
-static int fsfilt_ext3_iocontrol(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int rc = 0;
- ENTRY;
-
- /* FIXME: Can't do this because of nested transaction deadlock */
- if (cmd == EXT3_IOC_SETFLAGS) {
- /* We can't enable data journaling on OST objects, because
- * this forces the transaction to be closed in order to
- * flush the journal, but the caller will already have a
- * compound transaction open to update the last_rcvd file,
- * and this thread would deadlock trying to set the flag. */
- if ((*(int *)arg) & EXT3_JOURNAL_DATA_FL) {
- CERROR("can't set data journal flag on file\n");
- RETURN(-EPERM);
- }
- /* Because the MDS does not see the EXTENTS_FL set on the
- * OST objects, mask this flag into all set flags. It is
- * not legal to clear this flag in any case, so we are not
- * changing the functionality by doing this. b=22911 */
- *(int *)arg |= EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL;
- }
-
- /* ext4_ioctl does not have a inode argument */
- if (inode->i_fop->unlocked_ioctl)
- rc = inode->i_fop->unlocked_ioctl(file, cmd, arg);
- else
- RETURN(-ENOTTY);
-
- RETURN(rc);
-}
-
-static int fsfilt_ext3_set_md(struct inode *inode, void *handle,
- void *lmm, int lmm_size, const char *name)
-{
- int rc;
-
- LASSERT(mutex_trylock(&inode->i_mutex) == 0);
-
- rc = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_TRUSTED,
- name, lmm, lmm_size, XATTR_NO_CTIME);
-
- if (rc && rc != -EROFS)
- CERROR("error adding MD data to inode %lu: rc = %d\n",
- inode->i_ino, rc);
- return rc;
-}
-
-/* Must be called with i_mutex held */
-static int fsfilt_ext3_get_md(struct inode *inode, void *lmm, int lmm_size,
- const char *name)
-{
- int rc;
-
- LASSERT(mutex_trylock(&inode->i_mutex) == 0);
-
- rc = ext3_xattr_get(inode, EXT3_XATTR_INDEX_TRUSTED,
- name, lmm, lmm_size);
-
- /* This gives us the MD size */
- if (lmm == NULL)
- return (rc == -ENODATA) ? 0 : rc;
-
- if (rc < 0) {
- CDEBUG(D_INFO, "error getting EA %d/%s from inode %lu: rc %d\n",
- EXT3_XATTR_INDEX_TRUSTED, name,
- inode->i_ino, rc);
- memset(lmm, 0, lmm_size);
- return (rc == -ENODATA) ? 0 : rc;
- }
-
- return rc;
-}
-
-static int fsfilt_ext3_send_bio(int rw, struct inode *inode, struct bio *bio)
-{
- submit_bio(rw, bio);
- return 0;
-}
-
-static ssize_t fsfilt_ext3_readpage(struct file *file, char *buf, size_t count,
- loff_t *off)
-{
- struct inode *inode = file->f_dentry->d_inode;
- int rc = 0;
-
- if (S_ISREG(inode->i_mode))
- rc = file->f_op->read(file, buf, count, off);
- else {
- const int blkbits = inode->i_sb->s_blocksize_bits;
- const int blksize = inode->i_sb->s_blocksize;
-
- CDEBUG(D_EXT2, "reading %lu at dir %lu+%llu\n",
- (unsigned long)count, inode->i_ino, *off);
- while (count > 0) {
- struct buffer_head *bh;
-
- bh = NULL;
- if (*off < i_size_read(inode)) {
- int err = 0;
-
- bh = ext3_bread(NULL, inode, *off >> blkbits,
- 0, &err);
-
- CDEBUG(D_EXT2, "read %u@%llu\n", blksize, *off);
-
- if (bh) {
- memcpy(buf, bh->b_data, blksize);
- brelse(bh);
- } else if (err) {
- /* XXX in theory we should just fake
- * this buffer and continue like ext3,
- * especially if this is a partial read
- */
- CERROR("error read dir %lu+%llu: %d\n",
- inode->i_ino, *off, err);
- RETURN(err);
- }
- }
- if (!bh) {
- struct ext3_dir_entry_2 *fake = (void *)buf;
-
- CDEBUG(D_EXT2, "fake %u@%llu\n", blksize, *off);
- memset(fake, 0, sizeof(*fake));
- fake->rec_len = cpu_to_le16(blksize);
- }
- count -= blksize;
- buf += blksize;
- *off += blksize;
- rc += blksize;
- }
- }
-
- return rc;
-}
-
-#ifdef HAVE_EXT4_JOURNAL_CALLBACK_ADD
-static void fsfilt_ext3_cb_func(struct super_block *sb,
- struct journal_callback *jcb, int error)
-#else
-static void fsfilt_ext3_cb_func(struct journal_callback *jcb, int error)
-#endif
-{
- struct fsfilt_cb_data *fcb = container_of(jcb, typeof(*fcb), cb_jcb);
-
- fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, fcb->cb_data, error);
-
- OBD_SLAB_FREE(fcb, fcb_cache, sizeof *fcb);
-}
-
-static int fsfilt_ext3_add_journal_cb(struct obd_device *obd, __u64 last_rcvd,
- void *handle, fsfilt_cb_t cb_func,
- void *cb_data)
-{
- struct fsfilt_cb_data *fcb;
-
- OBD_SLAB_ALLOC_PTR_GFP(fcb, fcb_cache, CFS_ALLOC_IO);
- if (fcb == NULL)
- RETURN(-ENOMEM);
-
- fcb->cb_func = cb_func;
- fcb->cb_obd = obd;
- fcb->cb_last_rcvd = last_rcvd;
- fcb->cb_data = cb_data;
-
- CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
- fsfilt_journal_callback_set(handle, fsfilt_ext3_cb_func, &fcb->cb_jcb);
-
- return 0;
-}
-
-static int fsfilt_ext3_statfs(struct super_block *sb, struct obd_statfs *osfs)
-{
- struct kstatfs sfs;
- int rc;
-
- memset(&sfs, 0, sizeof(sfs));
- rc = sb->s_op->statfs(sb->s_root, &sfs);
- statfs_pack(osfs, &sfs);
- return rc;
-}
-
-static int fsfilt_ext3_sync(struct super_block *sb)
-{
- return ext3_force_commit(sb);
-}
-