|
@@ -313,7 +313,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- inode = gfs2_dir_search(dir, name);
|
|
|
+ inode = gfs2_dir_search(dir, name, false);
|
|
|
if (IS_ERR(inode))
|
|
|
error = PTR_ERR(inode);
|
|
|
out:
|
|
@@ -346,17 +346,6 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
|
|
|
if (!dip->i_inode.i_nlink)
|
|
|
return -ENOENT;
|
|
|
|
|
|
- error = gfs2_dir_check(&dip->i_inode, name, NULL);
|
|
|
- switch (error) {
|
|
|
- case -ENOENT:
|
|
|
- error = 0;
|
|
|
- break;
|
|
|
- case 0:
|
|
|
- return -EEXIST;
|
|
|
- default:
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
if (dip->i_entries == (u32)-1)
|
|
|
return -EFBIG;
|
|
|
if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1)
|
|
@@ -546,6 +535,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
|
|
|
* gfs2_create_inode - Create a new inode
|
|
|
* @dir: The parent directory
|
|
|
* @dentry: The new dentry
|
|
|
+ * @file: If non-NULL, the file which is being opened
|
|
|
* @mode: The permissions on the new inode
|
|
|
* @dev: For device nodes, this is the device number
|
|
|
* @symname: For symlinks, this is the link destination
|
|
@@ -555,8 +545,9 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
|
|
|
*/
|
|
|
|
|
|
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|
|
+ struct file *file,
|
|
|
umode_t mode, dev_t dev, const char *symname,
|
|
|
- unsigned int size, int excl)
|
|
|
+ unsigned int size, int excl, int *opened)
|
|
|
{
|
|
|
const struct qstr *name = &dentry->d_name;
|
|
|
struct gfs2_holder ghs[2];
|
|
@@ -564,6 +555,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|
|
struct gfs2_inode *dip = GFS2_I(dir), *ip;
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
|
|
|
struct gfs2_glock *io_gl;
|
|
|
+ struct dentry *d;
|
|
|
int error;
|
|
|
u32 aflags = 0;
|
|
|
int arq;
|
|
@@ -584,15 +576,30 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|
|
goto fail;
|
|
|
|
|
|
error = create_ok(dip, name, mode);
|
|
|
- if ((error == -EEXIST) && S_ISREG(mode) && !excl) {
|
|
|
- inode = gfs2_lookupi(dir, &dentry->d_name, 0);
|
|
|
- gfs2_glock_dq_uninit(ghs);
|
|
|
- d_instantiate(dentry, inode);
|
|
|
- return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
|
|
- }
|
|
|
if (error)
|
|
|
goto fail_gunlock;
|
|
|
|
|
|
+ inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl);
|
|
|
+ error = PTR_ERR(inode);
|
|
|
+ if (!IS_ERR(inode)) {
|
|
|
+ d = d_splice_alias(inode, dentry);
|
|
|
+ error = 0;
|
|
|
+ if (file && !IS_ERR(d)) {
|
|
|
+ if (d == NULL)
|
|
|
+ d = dentry;
|
|
|
+ if (S_ISREG(inode->i_mode))
|
|
|
+ error = finish_open(file, d, gfs2_open_common, opened);
|
|
|
+ else
|
|
|
+ error = finish_no_open(file, d);
|
|
|
+ }
|
|
|
+ gfs2_glock_dq_uninit(ghs);
|
|
|
+ if (IS_ERR(d))
|
|
|
+ return PTR_RET(d);
|
|
|
+ return error;
|
|
|
+ } else if (error != -ENOENT) {
|
|
|
+ goto fail_gunlock;
|
|
|
+ }
|
|
|
+
|
|
|
arq = error = gfs2_diradd_alloc_required(dir, name);
|
|
|
if (error < 0)
|
|
|
goto fail_gunlock;
|
|
@@ -686,10 +693,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|
|
goto fail_gunlock3;
|
|
|
|
|
|
mark_inode_dirty(inode);
|
|
|
+ d_instantiate(dentry, inode);
|
|
|
+ if (file)
|
|
|
+ error = finish_open(file, dentry, gfs2_open_common, opened);
|
|
|
gfs2_glock_dq_uninit(ghs);
|
|
|
gfs2_glock_dq_uninit(ghs + 1);
|
|
|
- d_instantiate(dentry, inode);
|
|
|
- return 0;
|
|
|
+ return error;
|
|
|
|
|
|
fail_gunlock3:
|
|
|
gfs2_glock_dq_uninit(ghs + 1);
|
|
@@ -729,36 +738,56 @@ fail:
|
|
|
static int gfs2_create(struct inode *dir, struct dentry *dentry,
|
|
|
umode_t mode, bool excl)
|
|
|
{
|
|
|
- return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
|
|
|
+ return gfs2_create_inode(dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, excl, NULL);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * gfs2_lookup - Look up a filename in a directory and return its inode
|
|
|
+ * __gfs2_lookup - Look up a filename in a directory and return its inode
|
|
|
* @dir: The directory inode
|
|
|
* @dentry: The dentry of the new inode
|
|
|
- * @nd: passed from Linux VFS, ignored by us
|
|
|
+ * @file: File to be opened
|
|
|
+ * @opened: atomic_open flags
|
|
|
*
|
|
|
- * Called by the VFS layer. Lock dir and call gfs2_lookupi()
|
|
|
*
|
|
|
* Returns: errno
|
|
|
*/
|
|
|
|
|
|
-static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
|
|
- unsigned int flags)
|
|
|
+static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
|
|
+ struct file *file, int *opened)
|
|
|
{
|
|
|
- struct inode *inode = gfs2_lookupi(dir, &dentry->d_name, 0);
|
|
|
- if (inode && !IS_ERR(inode)) {
|
|
|
- struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
|
|
|
- struct gfs2_holder gh;
|
|
|
- int error;
|
|
|
- error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
|
|
|
- if (error) {
|
|
|
- iput(inode);
|
|
|
- return ERR_PTR(error);
|
|
|
- }
|
|
|
- gfs2_glock_dq_uninit(&gh);
|
|
|
+ struct inode *inode;
|
|
|
+ struct dentry *d;
|
|
|
+ struct gfs2_holder gh;
|
|
|
+ struct gfs2_glock *gl;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ inode = gfs2_lookupi(dir, &dentry->d_name, 0);
|
|
|
+ if (!inode)
|
|
|
+ return NULL;
|
|
|
+ if (IS_ERR(inode))
|
|
|
+ return ERR_CAST(inode);
|
|
|
+
|
|
|
+ gl = GFS2_I(inode)->i_gl;
|
|
|
+ error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
|
|
|
+ if (error) {
|
|
|
+ iput(inode);
|
|
|
+ return ERR_PTR(error);
|
|
|
}
|
|
|
- return d_splice_alias(inode, dentry);
|
|
|
+
|
|
|
+ d = d_splice_alias(inode, dentry);
|
|
|
+ if (file && S_ISREG(inode->i_mode))
|
|
|
+ error = finish_open(file, dentry, gfs2_open_common, opened);
|
|
|
+
|
|
|
+ gfs2_glock_dq_uninit(&gh);
|
|
|
+ if (error)
|
|
|
+ return ERR_PTR(error);
|
|
|
+ return d;
|
|
|
+}
|
|
|
+
|
|
|
+static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
|
|
+ unsigned flags)
|
|
|
+{
|
|
|
+ return __gfs2_lookup(dir, dentry, NULL, NULL);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1076,7 +1105,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
|
|
|
if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
|
|
|
return -ENAMETOOLONG;
|
|
|
|
|
|
- return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size, 0);
|
|
|
+ return gfs2_create_inode(dir, dentry, NULL, S_IFLNK | S_IRWXUGO, 0, symname, size, 0, NULL);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1092,7 +1121,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
|
{
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(dir);
|
|
|
unsigned dsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
|
|
|
- return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, dsize, 0);
|
|
|
+ return gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0, NULL);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1107,7 +1136,43 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
|
static int gfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|
|
dev_t dev)
|
|
|
{
|
|
|
- return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0, 0);
|
|
|
+ return gfs2_create_inode(dir, dentry, NULL, mode, dev, NULL, 0, 0, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * gfs2_atomic_open - Atomically open a file
|
|
|
+ * @dir: The directory
|
|
|
+ * @dentry: The proposed new entry
|
|
|
+ * @file: The proposed new struct file
|
|
|
+ * @flags: open flags
|
|
|
+ * @mode: File mode
|
|
|
+ * @opened: Flag to say whether the file has been opened or not
|
|
|
+ *
|
|
|
+ * Returns: error code or 0 for success
|
|
|
+ */
|
|
|
+
|
|
|
+static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
|
|
|
+ struct file *file, unsigned flags,
|
|
|
+ umode_t mode, int *opened)
|
|
|
+{
|
|
|
+ struct dentry *d;
|
|
|
+ bool excl = !!(flags & O_EXCL);
|
|
|
+
|
|
|
+ d = __gfs2_lookup(dir, dentry, file, opened);
|
|
|
+ if (IS_ERR(d))
|
|
|
+ return PTR_ERR(d);
|
|
|
+ if (d == NULL)
|
|
|
+ d = dentry;
|
|
|
+ if (d->d_inode) {
|
|
|
+ if (!(*opened & FILE_OPENED))
|
|
|
+ return finish_no_open(file, d);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(flags & O_CREAT))
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ return gfs2_create_inode(dir, dentry, file, S_IFREG | mode, 0, NULL, 0, excl, opened);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1787,6 +1852,7 @@ const struct inode_operations gfs2_dir_iops = {
|
|
|
.removexattr = gfs2_removexattr,
|
|
|
.fiemap = gfs2_fiemap,
|
|
|
.get_acl = gfs2_get_acl,
|
|
|
+ .atomic_open = gfs2_atomic_open,
|
|
|
};
|
|
|
|
|
|
const struct inode_operations gfs2_symlink_iops = {
|