GFS2: Add atomic_open support
I've restricted atomic_open to only operate on regular files, although I still don't understand why atomic_open should not be possible also for directories on GFS2. That can always be added in later though, if it makes sense. The ->atomic_open function can be passed negative dentries, which in most cases means either ENOENT (->lookup) or a call to d_instantiate (->create). In the GFS2 case though, we need to actually perform the look up, since we do not know whether there has been a new inode created on another node. The look up calls d_splice_alias which then tries to rehash the dentry - so the solution here is to simply check for that in d_splice_alias. The same issue is likely to affect any other cluster filesystem implementing ->atomic_open Signed-off-by: Steven Whitehouse <swhiteho@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: "J. Bruce Fields" <bfields fieldses org> Cc: Jeff Layton <jlayton@redhat.com>
Šī revīzija ir iekļauta:
@@ -537,11 +537,52 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_open_common - This is common to open and atomic_open
|
||||
* @inode: The inode being opened
|
||||
* @file: The file being opened
|
||||
*
|
||||
* This maybe called under a glock or not depending upon how it has
|
||||
* been called. We must always be called under a glock for regular
|
||||
* files, however. For other file types, it does not matter whether
|
||||
* we hold the glock or not.
|
||||
*
|
||||
* Returns: Error code or 0 for success
|
||||
*/
|
||||
|
||||
int gfs2_open_common(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct gfs2_file *fp;
|
||||
int ret;
|
||||
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
ret = generic_file_open(inode, file);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fp = kzalloc(sizeof(struct gfs2_file), GFP_NOFS);
|
||||
if (!fp)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&fp->f_fl_mutex);
|
||||
|
||||
gfs2_assert_warn(GFS2_SB(inode), !file->private_data);
|
||||
file->private_data = fp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_open - open a file
|
||||
* @inode: the inode to open
|
||||
* @file: the struct file for this opening
|
||||
*
|
||||
* After atomic_open, this function is only used for opening files
|
||||
* which are already cached. We must still get the glock for regular
|
||||
* files to ensure that we have the file size uptodate for the large
|
||||
* file check which is in the common code. That is only an issue for
|
||||
* regular files though.
|
||||
*
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
@@ -549,40 +590,22 @@ static int gfs2_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_holder i_gh;
|
||||
struct gfs2_file *fp;
|
||||
int error;
|
||||
|
||||
fp = kzalloc(sizeof(struct gfs2_file), GFP_KERNEL);
|
||||
if (!fp)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&fp->f_fl_mutex);
|
||||
|
||||
gfs2_assert_warn(GFS2_SB(inode), !file->private_data);
|
||||
file->private_data = fp;
|
||||
bool need_unlock = false;
|
||||
|
||||
if (S_ISREG(ip->i_inode.i_mode)) {
|
||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
|
||||
&i_gh);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
if (!(file->f_flags & O_LARGEFILE) &&
|
||||
i_size_read(inode) > MAX_NON_LFS) {
|
||||
error = -EOVERFLOW;
|
||||
goto fail_gunlock;
|
||||
}
|
||||
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
return error;
|
||||
need_unlock = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
error = gfs2_open_common(inode, file);
|
||||
|
||||
if (need_unlock)
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
|
||||
fail_gunlock:
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
fail:
|
||||
file->private_data = NULL;
|
||||
kfree(fp);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
Atsaukties uz šo jaunā problēmā
Block a user