linux/fs/gfs2/export.c
Linus Torvalds d8c8e595dc dlm for 6.8
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()
2024-01-10 10:17:23 -08:00

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,
};