#include <linux/posix_acl.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
-#include <linux/lm_interface.h>
+#include <linux/fiemap.h>
#include <asm/uaccess.h>
#include "gfs2.h"
#include "glock.h"
#include "inode.h"
#include "meta_io.h"
-#include "ops_dentry.h"
-#include "ops_inode.h"
#include "quota.h"
#include "rgrp.h"
#include "trans.h"
#include "util.h"
+#include "super.h"
/**
* gfs2_create - Create a file
mark_inode_dirty(inode);
break;
} else if (PTR_ERR(inode) != -EEXIST ||
- (nd && (nd->intent.open.flags & O_EXCL))) {
+ (nd && nd->flags & LOOKUP_EXCL)) {
gfs2_holder_uninit(ghs);
return PTR_ERR(inode);
}
if (!dip->i_inode.i_nlink)
goto out_gunlock;
error = -EFBIG;
- if (dip->i_di.di_entries == (u32)-1)
+ if (dip->i_entries == (u32)-1)
goto out_gunlock;
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
ip = ghs[1].gh_gl->gl_object;
- ip->i_di.di_size = size;
+ ip->i_disksize = size;
+ i_size_write(inode, size);
error = gfs2_meta_inode_buffer(ip, &dibh);
ip = ghs[1].gh_gl->gl_object;
ip->i_inode.i_nlink = 2;
- ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
- ip->i_di.di_flags |= GFS2_DIF_JDATA;
- ip->i_di.di_entries = 2;
+ ip->i_disksize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
+ ip->i_diskflags |= GFS2_DIF_JDATA;
+ ip->i_entries = 2;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
goto out_gunlock;
- if (ip->i_di.di_entries < 2) {
+ if (ip->i_entries < 2) {
if (gfs2_consist_inode(ip))
gfs2_dinode_print(ip);
error = -EIO;
goto out_gunlock;
}
- if (ip->i_di.di_entries > 2) {
+ if (ip->i_entries > 2) {
error = -ENOTEMPTY;
goto out_gunlock;
}
return 0;
}
+/*
+ * gfs2_ok_to_move - check if it's ok to move a directory to another directory
+ * @this: move this
+ * @to: to here
+ *
+ * Follow @to back to the root and make sure we don't encounter @this
+ * Assumes we already hold the rename lock.
+ *
+ * Returns: errno
+ */
+
+static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
+{
+ struct inode *dir = &to->i_inode;
+ struct super_block *sb = dir->i_sb;
+ struct inode *tmp;
+ struct qstr dotdot;
+ int error = 0;
+
+ gfs2_str2qstr(&dotdot, "..");
+
+ igrab(dir);
+
+ for (;;) {
+ if (dir == &this->i_inode) {
+ error = -EINVAL;
+ break;
+ }
+ if (dir == sb->s_root->d_inode) {
+ error = 0;
+ break;
+ }
+
+ tmp = gfs2_lookupi(dir, &dotdot, 1);
+ if (IS_ERR(tmp)) {
+ error = PTR_ERR(tmp);
+ break;
+ }
+
+ iput(dir);
+ dir = tmp;
+ }
+
+ iput(dir);
+
+ return error;
+}
+
/**
* gfs2_rename - Rename a file
* @odir: Parent directory of old file name
struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
struct gfs2_inode *nip = NULL;
struct gfs2_sbd *sdp = GFS2_SB(odir);
- struct gfs2_holder ghs[5], r_gh;
+ struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
struct gfs2_rgrpd *nrgd;
unsigned int num_gh;
int dir_rename = 0;
return 0;
}
- /* Make sure we aren't trying to move a dirctory into it's subdir */
- if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) {
- dir_rename = 1;
-
- error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0,
- &r_gh);
+ if (odip != ndip) {
+ error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
+ 0, &r_gh);
if (error)
goto out;
- error = gfs2_ok_to_move(ip, ndip);
- if (error)
- goto out_gunlock_r;
+ if (S_ISDIR(ip->i_inode.i_mode)) {
+ dir_rename = 1;
+ /* don't move a dirctory into it's subdir */
+ error = gfs2_ok_to_move(ip, ndip);
+ if (error)
+ goto out_gunlock_r;
+ }
}
num_gh = 1;
goto out_gunlock;
if (S_ISDIR(nip->i_inode.i_mode)) {
- if (nip->i_di.di_entries < 2) {
+ if (nip->i_entries < 2) {
if (gfs2_consist_inode(nip))
gfs2_dinode_print(nip);
error = -EIO;
goto out_gunlock;
}
- if (nip->i_di.di_entries > 2) {
+ if (nip->i_entries > 2) {
error = -ENOTEMPTY;
goto out_gunlock;
}
error = -EINVAL;
goto out_gunlock;
}
- if (ndip->i_di.di_entries == (u32)-1) {
+ if (ndip->i_entries == (u32)-1) {
error = -EFBIG;
goto out_gunlock;
}
gfs2_holder_uninit(ghs + x);
}
out_gunlock_r:
- if (dir_rename)
+ if (r_gh.gh_gl)
gfs2_glock_dq_uninit(&r_gh);
out:
return error;
struct gfs2_sbd *sdp = GFS2_SB(inode);
int error;
- if (attr->ia_size != ip->i_di.di_size) {
+ if (attr->ia_size != ip->i_disksize) {
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
if (error)
return error;
}
error = gfs2_truncatei(ip, attr->ia_size);
- if (error && (inode->i_size != ip->i_di.di_size))
- i_size_write(inode, ip->i_di.di_size);
+ if (error && (inode->i_size != ip->i_disksize))
+ i_size_write(inode, ip->i_disksize);
return error;
}
return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er);
}
+static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+ u64 start, u64 len)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder gh;
+ int ret;
+
+ ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
+ if (ret)
+ return ret;
+
+ mutex_lock(&inode->i_mutex);
+
+ ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
+ if (ret)
+ goto out;
+
+ if (gfs2_is_stuffed(ip)) {
+ u64 phys = ip->i_no_addr << inode->i_blkbits;
+ u64 size = i_size_read(inode);
+ u32 flags = FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_NOT_ALIGNED|
+ FIEMAP_EXTENT_DATA_INLINE;
+ phys += sizeof(struct gfs2_dinode);
+ phys += start;
+ if (start + len > size)
+ len = size - start;
+ if (start < size)
+ ret = fiemap_fill_next_extent(fieinfo, start, phys,
+ len, flags);
+ if (ret == 1)
+ ret = 0;
+ } else {
+ ret = __generic_block_fiemap(inode, fieinfo, start, len,
+ gfs2_block_map);
+ }
+
+ gfs2_glock_dq_uninit(&gh);
+out:
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+}
+
const struct inode_operations gfs2_file_iops = {
.permission = gfs2_permission,
.setattr = gfs2_setattr,
.getxattr = gfs2_getxattr,
.listxattr = gfs2_listxattr,
.removexattr = gfs2_removexattr,
+ .fiemap = gfs2_fiemap,
};
const struct inode_operations gfs2_dir_iops = {
.getxattr = gfs2_getxattr,
.listxattr = gfs2_listxattr,
.removexattr = gfs2_removexattr,
+ .fiemap = gfs2_fiemap,
};
const struct inode_operations gfs2_symlink_iops = {
.getxattr = gfs2_getxattr,
.listxattr = gfs2_listxattr,
.removexattr = gfs2_removexattr,
+ .fiemap = gfs2_fiemap,
};