d8c8e595dc
This set cleans up the interface between nfs lockd and dlm, which is handling nfs file locking for gfs2 and ocfs2. Very basic lockd functionality is fixed, in which the fl owner was using the lockd pid instead of the owner value from nfs. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEcGkeEvkvjdvlR90nOBtzx/yAaaoFAmWDZFwACgkQOBtzx/yA aapu/hAAx/9ahq4Vm+T7Lpw6wGEKISUi5djZlqrN7EddHcyAMFFX/41PkOez9KJT Rr4Mp+MBB6xjDDco4uVZxhnWJCI6RKExSB4N+eMx0Rhs09Ksf8UCtxTvKaDa18fr ZwPmGNpE/a3khTkwC5h/98m8kOyYIqSOL8/cR8zGytkHkgDiyv4VqD0cHAvwxR5a O8jQDtssXld6sF5GxhVQnLQiu0eVfFLlaaSsb28ju+yMPVOTDxmwNkP3eP+8d1le lcNp82+C7UmzO5Ds1/SgBIJZoej/xipz00BAlGH1oieD4xRLCbkoJSQsGxpkPwEI I1V8fd7zaFQ1VnDHMeMrjl46qjUQKkCfDK/v9BCvN5x8sCqaqUydMQ0mD/424NXe A/JgjAtloIhIOqmX/K/h4jioTrFlVevtTAr9Cv/sq31VX0+ALJVS3ccbhv68gjiW Cflef7Va53mXYfIAs6qc60/ArpvrPUG7Bna4aIb5iVJj4z/OOjnTxyZVOD3wJetY bs4w2dSrafX589EN/gIyKka3iOMcJS7wVsvRME9KYVikNbHgQrSpsixHPlLdjGq+ cHbozutVQYnhaGI608yMjPZ+rXu5jYEfAIQnI8FABbi4VR29+SnzxrZllMICUZ+Y pfRQ6YkiuBRy2HSbnwudemj6iSrPqZEts2GDkqj2LDfkMWeycKM= =UBeR -----END PGP SIGNATURE----- Merge tag 'dlm-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm Pull dlm updates from David Teigland: "This set cleans up the interface between nfs lockd and dlm, which is handling nfs file locking for gfs2 and ocfs2. Very basic lockd functionality is fixed, in which the fl owner was using the lockd pid instead of the owner value from nfs" * tag 'dlm-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm: dlm: update format header reflect current format dlm: fix format seq ops type 4 dlm: implement EXPORT_OP_ASYNC_LOCK dlm: use FL_SLEEP to determine blocking vs non-blocking dlm: use fl_owner from lockd dlm: use kernel_connect() and kernel_bind()
196 lines
4.6 KiB
C
196 lines
4.6 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
|
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/spinlock.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/buffer_head.h>
|
|
#include <linux/exportfs.h>
|
|
#include <linux/gfs2_ondisk.h>
|
|
#include <linux/crc32.h>
|
|
|
|
#include "gfs2.h"
|
|
#include "incore.h"
|
|
#include "dir.h"
|
|
#include "glock.h"
|
|
#include "glops.h"
|
|
#include "inode.h"
|
|
#include "super.h"
|
|
#include "rgrp.h"
|
|
#include "util.h"
|
|
|
|
#define GFS2_SMALL_FH_SIZE 4
|
|
#define GFS2_LARGE_FH_SIZE 8
|
|
#define GFS2_OLD_FH_SIZE 10
|
|
|
|
static int gfs2_encode_fh(struct inode *inode, __u32 *p, int *len,
|
|
struct inode *parent)
|
|
{
|
|
__be32 *fh = (__force __be32 *)p;
|
|
struct super_block *sb = inode->i_sb;
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
|
|
|
if (parent && (*len < GFS2_LARGE_FH_SIZE)) {
|
|
*len = GFS2_LARGE_FH_SIZE;
|
|
return FILEID_INVALID;
|
|
} else if (*len < GFS2_SMALL_FH_SIZE) {
|
|
*len = GFS2_SMALL_FH_SIZE;
|
|
return FILEID_INVALID;
|
|
}
|
|
|
|
fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
|
|
fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
|
|
fh[2] = cpu_to_be32(ip->i_no_addr >> 32);
|
|
fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
|
|
*len = GFS2_SMALL_FH_SIZE;
|
|
|
|
if (!parent || inode == d_inode(sb->s_root))
|
|
return *len;
|
|
|
|
ip = GFS2_I(parent);
|
|
|
|
fh[4] = cpu_to_be32(ip->i_no_formal_ino >> 32);
|
|
fh[5] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
|
|
fh[6] = cpu_to_be32(ip->i_no_addr >> 32);
|
|
fh[7] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
|
|
*len = GFS2_LARGE_FH_SIZE;
|
|
|
|
return *len;
|
|
}
|
|
|
|
struct get_name_filldir {
|
|
struct dir_context ctx;
|
|
struct gfs2_inum_host inum;
|
|
char *name;
|
|
};
|
|
|
|
static bool get_name_filldir(struct dir_context *ctx, const char *name,
|
|
int length, loff_t offset, u64 inum,
|
|
unsigned int type)
|
|
{
|
|
struct get_name_filldir *gnfd =
|
|
container_of(ctx, struct get_name_filldir, ctx);
|
|
|
|
if (inum != gnfd->inum.no_addr)
|
|
return true;
|
|
|
|
memcpy(gnfd->name, name, length);
|
|
gnfd->name[length] = 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
static int gfs2_get_name(struct dentry *parent, char *name,
|
|
struct dentry *child)
|
|
{
|
|
struct inode *dir = d_inode(parent);
|
|
struct inode *inode = d_inode(child);
|
|
struct gfs2_inode *dip, *ip;
|
|
struct get_name_filldir gnfd = {
|
|
.ctx.actor = get_name_filldir,
|
|
.name = name
|
|
};
|
|
struct gfs2_holder gh;
|
|
int error;
|
|
struct file_ra_state f_ra = { .start = 0 };
|
|
|
|
if (!dir)
|
|
return -EINVAL;
|
|
|
|
if (!S_ISDIR(dir->i_mode) || !inode)
|
|
return -EINVAL;
|
|
|
|
dip = GFS2_I(dir);
|
|
ip = GFS2_I(inode);
|
|
|
|
*name = 0;
|
|
gnfd.inum.no_addr = ip->i_no_addr;
|
|
gnfd.inum.no_formal_ino = ip->i_no_formal_ino;
|
|
|
|
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
|
|
if (error)
|
|
return error;
|
|
|
|
error = gfs2_dir_read(dir, &gnfd.ctx, &f_ra);
|
|
|
|
gfs2_glock_dq_uninit(&gh);
|
|
|
|
if (!error && !*name)
|
|
error = -ENOENT;
|
|
|
|
return error;
|
|
}
|
|
|
|
static struct dentry *gfs2_get_parent(struct dentry *child)
|
|
{
|
|
return d_obtain_alias(gfs2_lookupi(d_inode(child), &gfs2_qdotdot, 1));
|
|
}
|
|
|
|
static struct dentry *gfs2_get_dentry(struct super_block *sb,
|
|
struct gfs2_inum_host *inum)
|
|
{
|
|
struct gfs2_sbd *sdp = sb->s_fs_info;
|
|
struct inode *inode;
|
|
|
|
if (!inum->no_formal_ino)
|
|
return ERR_PTR(-ESTALE);
|
|
inode = gfs2_lookup_by_inum(sdp, inum->no_addr, inum->no_formal_ino,
|
|
GFS2_BLKST_DINODE);
|
|
return d_obtain_alias(inode);
|
|
}
|
|
|
|
static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
|
int fh_len, int fh_type)
|
|
{
|
|
struct gfs2_inum_host this;
|
|
__be32 *fh = (__force __be32 *)fid->raw;
|
|
|
|
switch (fh_type) {
|
|
case GFS2_SMALL_FH_SIZE:
|
|
case GFS2_LARGE_FH_SIZE:
|
|
case GFS2_OLD_FH_SIZE:
|
|
if (fh_len < GFS2_SMALL_FH_SIZE)
|
|
return NULL;
|
|
this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
|
|
this.no_formal_ino |= be32_to_cpu(fh[1]);
|
|
this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
|
|
this.no_addr |= be32_to_cpu(fh[3]);
|
|
return gfs2_get_dentry(sb, &this);
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
|
|
int fh_len, int fh_type)
|
|
{
|
|
struct gfs2_inum_host parent;
|
|
__be32 *fh = (__force __be32 *)fid->raw;
|
|
|
|
switch (fh_type) {
|
|
case GFS2_LARGE_FH_SIZE:
|
|
case GFS2_OLD_FH_SIZE:
|
|
if (fh_len < GFS2_LARGE_FH_SIZE)
|
|
return NULL;
|
|
parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
|
|
parent.no_formal_ino |= be32_to_cpu(fh[5]);
|
|
parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
|
|
parent.no_addr |= be32_to_cpu(fh[7]);
|
|
return gfs2_get_dentry(sb, &parent);
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
const struct export_operations gfs2_export_ops = {
|
|
.encode_fh = gfs2_encode_fh,
|
|
.fh_to_dentry = gfs2_fh_to_dentry,
|
|
.fh_to_parent = gfs2_fh_to_parent,
|
|
.get_name = gfs2_get_name,
|
|
.get_parent = gfs2_get_parent,
|
|
.flags = EXPORT_OP_ASYNC_LOCK,
|
|
};
|
|
|