GFS2: Add a "demote a glock" interface to sysfs
authorSteven Whitehouse <swhiteho@redhat.com>
Thu, 12 Feb 2009 13:31:58 +0000 (13:31 +0000)
committerSteven Whitehouse <steve@dolmen.chygwyn.com>
Tue, 24 Mar 2009 11:21:22 +0000 (11:21 +0000)
This adds a sysfs file called demote_rq to GFS2's
per filesystem directory. Its possible to use this
file to demote arbitrary glocks in exactly the same
way as if a request had come in from a remote node.

This is intended for testing issues relating to caching
of data under glocks. Despite that, the interface is
generic enough to send requests to any type of glock,
but be careful as its not always safe to send an
arbitrary message to an arbitrary glock. For that reason
and to prevent DoS, this interface is restricted to root
only.

The messages look like this:

<type>:<glocknumber> <mode>

Example:

echo -n "2:13324 EX" >/sys/fs/gfs2/unity:myfs/demote_rq

Which means "please demote inode glock (type 2) number 13324 so that
I can get an EX (exclusive) lock". The lock modes are those which
would normally be sent by a remote node in its callback so if you
want to unlock a glock, you use EX, to demote to shared, use SH or PR
(depending on whether you like GFS2 or DLM lock modes better!).

If the glock doesn't exist, you'll get -ENOENT returned. If the
arguments don't make sense, you'll get -EINVAL returned.

The plan is that this interface will be used in combination with
the blktrace patch which I recently posted for comments although
it is, of course, still useful in its own right.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/glops.h
fs/gfs2/rgrp.c
fs/gfs2/sys.c

index ad8e121427c0c016895e19cf96c3d061c1ba1a88..3984e47d1d334dbb6112e3e2f99a91c76f55daa1 100644 (file)
@@ -684,10 +684,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        gl = search_bucket(hash, sdp, &name);
        read_unlock(gl_lock_addr(hash));
 
-       if (gl || !create) {
-               *glp = gl;
+       *glp = gl;
+       if (gl)
                return 0;
-       }
+       if (!create)
+               return -ENOENT;
 
        gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL);
        if (!gl)
index a9b7d3a60081cca397f02fa6036aa9d8599a13f2..f34bc7093dd1d7236742ce6747054dcd28886f13 100644 (file)
@@ -447,3 +447,15 @@ const struct gfs2_glock_operations gfs2_journal_glops = {
        .go_type = LM_TYPE_JOURNAL,
 };
 
+const struct gfs2_glock_operations *gfs2_glops_list[] = {
+       [LM_TYPE_META] = &gfs2_meta_glops,
+       [LM_TYPE_INODE] = &gfs2_inode_glops,
+       [LM_TYPE_RGRP] = &gfs2_rgrp_glops,
+       [LM_TYPE_NONDISK] = &gfs2_trans_glops,
+       [LM_TYPE_IOPEN] = &gfs2_iopen_glops,
+       [LM_TYPE_FLOCK] = &gfs2_flock_glops,
+       [LM_TYPE_NONDISK] = &gfs2_nondisk_glops,
+       [LM_TYPE_QUOTA] = &gfs2_quota_glops,
+       [LM_TYPE_JOURNAL] = &gfs2_journal_glops,
+};
+
index a1d9b5b024e633af2a95069e4ba12c3a36268a68..b3aa2e3210fd6028cd5615a9c07a79ad5433af2c 100644 (file)
@@ -21,5 +21,6 @@ extern const struct gfs2_glock_operations gfs2_flock_glops;
 extern const struct gfs2_glock_operations gfs2_nondisk_glops;
 extern const struct gfs2_glock_operations gfs2_quota_glops;
 extern const struct gfs2_glock_operations gfs2_journal_glops;
+extern const struct gfs2_glock_operations *gfs2_glops_list[];
 
 #endif /* __GLOPS_DOT_H__ */
index 789953a2b6a8d9d7757203de4c0379bd0ec26a6f..a068ac940de1709c9d6e0e75abe1a6978ea3debb 100644 (file)
@@ -839,7 +839,7 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
        const unsigned int sects_per_blk = sdp->sd_sb.sb_bsize /
                                           bdev_hardsect_size(sb->s_bdev);
        u64 blk;
-       sector_t start;
+       sector_t start = 0;
        sector_t nr_sects = 0;
        int rv;
        unsigned int x;
index 4d284d14980b8ef4641ce78ba291dfb30a4298f7..7655f5025fec4868e7d00e5790abb5d85394a926 100644 (file)
@@ -24,6 +24,7 @@
 #include "glock.h"
 #include "quota.h"
 #include "util.h"
+#include "glops.h"
 
 static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
 {
@@ -171,6 +172,46 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
        return len;
 }
 
+static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+       struct gfs2_glock *gl;
+       const struct gfs2_glock_operations *glops;
+       unsigned int glmode;
+       unsigned int gltype;
+       unsigned long long glnum;
+       char mode[16];
+       int rv;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       rv = sscanf(buf, "%u:%llu %15s", &gltype, &glnum,
+                   mode);
+       if (rv != 3)
+               return -EINVAL;
+
+       if (strcmp(mode, "EX") == 0)
+               glmode = LM_ST_UNLOCKED;
+       else if ((strcmp(mode, "CW") == 0) || (strcmp(mode, "DF") == 0))
+               glmode = LM_ST_DEFERRED;
+       else if ((strcmp(mode, "PR") == 0) || (strcmp(mode, "SH") == 0))
+               glmode = LM_ST_SHARED;
+       else
+               return -EINVAL;
+
+       if (gltype > LM_TYPE_JOURNAL)
+               return -EINVAL;
+       glops = gfs2_glops_list[gltype];
+       if (glops == NULL)
+               return -EINVAL;
+       rv = gfs2_glock_get(sdp, glnum, glops, 0, &gl);
+       if (rv)
+               return rv;
+       gfs2_glock_cb(gl, glmode);
+       gfs2_glock_put(gl);
+       return len;
+}
+
 struct gfs2_attr {
        struct attribute attr;
        ssize_t (*show)(struct gfs2_sbd *, char *);
@@ -189,6 +230,7 @@ GFS2_ATTR(statfs_sync,         0200, NULL,          statfs_sync_store);
 GFS2_ATTR(quota_sync,          0200, NULL,          quota_sync_store);
 GFS2_ATTR(quota_refresh_user,  0200, NULL,          quota_refresh_user_store);
 GFS2_ATTR(quota_refresh_group, 0200, NULL,          quota_refresh_group_store);
+GFS2_ATTR(demote_rq,           0200, NULL,         demote_rq_store);
 
 static struct attribute *gfs2_attrs[] = {
        &gfs2_attr_id.attr,
@@ -200,6 +242,7 @@ static struct attribute *gfs2_attrs[] = {
        &gfs2_attr_quota_sync.attr,
        &gfs2_attr_quota_refresh_user.attr,
        &gfs2_attr_quota_refresh_group.attr,
+       &gfs2_attr_demote_rq.attr,
        NULL,
 };