|
@@ -18,6 +18,7 @@
|
|
#include <linux/crc32.h>
|
|
#include <linux/crc32.h>
|
|
#include <linux/lm_interface.h>
|
|
#include <linux/lm_interface.h>
|
|
#include <linux/security.h>
|
|
#include <linux/security.h>
|
|
|
|
+#include <linux/time.h>
|
|
|
|
|
|
#include "gfs2.h"
|
|
#include "gfs2.h"
|
|
#include "incore.h"
|
|
#include "incore.h"
|
|
@@ -249,6 +250,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
|
|
{
|
|
{
|
|
struct gfs2_dinode_host *di = &ip->i_di;
|
|
struct gfs2_dinode_host *di = &ip->i_di;
|
|
const struct gfs2_dinode *str = buf;
|
|
const struct gfs2_dinode *str = buf;
|
|
|
|
+ struct timespec atime;
|
|
u16 height, depth;
|
|
u16 height, depth;
|
|
|
|
|
|
if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
|
|
if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
|
|
@@ -275,8 +277,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
|
|
di->di_size = be64_to_cpu(str->di_size);
|
|
di->di_size = be64_to_cpu(str->di_size);
|
|
i_size_write(&ip->i_inode, di->di_size);
|
|
i_size_write(&ip->i_inode, di->di_size);
|
|
gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks));
|
|
gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks));
|
|
- ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime);
|
|
|
|
- ip->i_inode.i_atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
|
|
|
|
|
|
+ atime.tv_sec = be64_to_cpu(str->di_atime);
|
|
|
|
+ atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
|
|
|
|
+ if (timespec_compare(&ip->i_inode.i_atime, &atime) < 0)
|
|
|
|
+ ip->i_inode.i_atime = atime;
|
|
ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);
|
|
ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);
|
|
ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec);
|
|
ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec);
|
|
ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime);
|
|
ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime);
|
|
@@ -1157,8 +1161,8 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
|
|
unsigned int x;
|
|
unsigned int x;
|
|
int error;
|
|
int error;
|
|
|
|
|
|
- gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh);
|
|
|
|
- error = gfs2_glock_nq_atime(&i_gh);
|
|
|
|
|
|
+ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
|
|
|
|
+ error = gfs2_glock_nq(&i_gh);
|
|
if (error) {
|
|
if (error) {
|
|
gfs2_holder_uninit(&i_gh);
|
|
gfs2_holder_uninit(&i_gh);
|
|
return error;
|
|
return error;
|
|
@@ -1193,101 +1197,6 @@ out:
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
-/**
|
|
|
|
- * gfs2_glock_nq_atime - Acquire a hold on an inode's glock, and
|
|
|
|
- * conditionally update the inode's atime
|
|
|
|
- * @gh: the holder to acquire
|
|
|
|
- *
|
|
|
|
- * Tests atime (access time) for gfs2_read, gfs2_readdir and gfs2_mmap
|
|
|
|
- * Update if the difference between the current time and the inode's current
|
|
|
|
- * atime is greater than an interval specified at mount.
|
|
|
|
- *
|
|
|
|
- * Returns: errno
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
-int gfs2_glock_nq_atime(struct gfs2_holder *gh)
|
|
|
|
-{
|
|
|
|
- struct gfs2_glock *gl = gh->gh_gl;
|
|
|
|
- struct gfs2_sbd *sdp = gl->gl_sbd;
|
|
|
|
- struct gfs2_inode *ip = gl->gl_object;
|
|
|
|
- s64 quantum = gfs2_tune_get(sdp, gt_atime_quantum);
|
|
|
|
- unsigned int state;
|
|
|
|
- int flags;
|
|
|
|
- int error;
|
|
|
|
- struct timespec tv = CURRENT_TIME;
|
|
|
|
-
|
|
|
|
- if (gfs2_assert_warn(sdp, gh->gh_flags & GL_ATIME) ||
|
|
|
|
- gfs2_assert_warn(sdp, !(gh->gh_flags & GL_ASYNC)) ||
|
|
|
|
- gfs2_assert_warn(sdp, gl->gl_ops == &gfs2_inode_glops))
|
|
|
|
- return -EINVAL;
|
|
|
|
-
|
|
|
|
- state = gh->gh_state;
|
|
|
|
- flags = gh->gh_flags;
|
|
|
|
-
|
|
|
|
- error = gfs2_glock_nq(gh);
|
|
|
|
- if (error)
|
|
|
|
- return error;
|
|
|
|
-
|
|
|
|
- if (test_bit(SDF_NOATIME, &sdp->sd_flags) ||
|
|
|
|
- (sdp->sd_vfs->s_flags & MS_RDONLY))
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- if (tv.tv_sec - ip->i_inode.i_atime.tv_sec >= quantum) {
|
|
|
|
- gfs2_glock_dq(gh);
|
|
|
|
- gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY,
|
|
|
|
- gh);
|
|
|
|
- error = gfs2_glock_nq(gh);
|
|
|
|
- if (error)
|
|
|
|
- return error;
|
|
|
|
-
|
|
|
|
- /* Verify that atime hasn't been updated while we were
|
|
|
|
- trying to get exclusive lock. */
|
|
|
|
-
|
|
|
|
- tv = CURRENT_TIME;
|
|
|
|
- if (tv.tv_sec - ip->i_inode.i_atime.tv_sec >= quantum) {
|
|
|
|
- struct buffer_head *dibh;
|
|
|
|
- struct gfs2_dinode *di;
|
|
|
|
-
|
|
|
|
- error = gfs2_trans_begin(sdp, RES_DINODE, 0);
|
|
|
|
- if (error == -EROFS)
|
|
|
|
- return 0;
|
|
|
|
- if (error)
|
|
|
|
- goto fail;
|
|
|
|
-
|
|
|
|
- error = gfs2_meta_inode_buffer(ip, &dibh);
|
|
|
|
- if (error)
|
|
|
|
- goto fail_end_trans;
|
|
|
|
-
|
|
|
|
- ip->i_inode.i_atime = tv;
|
|
|
|
-
|
|
|
|
- gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
|
|
|
- di = (struct gfs2_dinode *)dibh->b_data;
|
|
|
|
- di->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec);
|
|
|
|
- di->di_atime_nsec = cpu_to_be32(ip->i_inode.i_atime.tv_nsec);
|
|
|
|
- brelse(dibh);
|
|
|
|
-
|
|
|
|
- gfs2_trans_end(sdp);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* If someone else has asked for the glock,
|
|
|
|
- unlock and let them have it. Then reacquire
|
|
|
|
- in the original state. */
|
|
|
|
- if (gfs2_glock_is_blocking(gl)) {
|
|
|
|
- gfs2_glock_dq(gh);
|
|
|
|
- gfs2_holder_reinit(state, flags, gh);
|
|
|
|
- return gfs2_glock_nq(gh);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
-fail_end_trans:
|
|
|
|
- gfs2_trans_end(sdp);
|
|
|
|
-fail:
|
|
|
|
- gfs2_glock_dq(gh);
|
|
|
|
- return error;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int
|
|
static int
|
|
__gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
|
|
__gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
|
|
{
|
|
{
|