From 5ac87ffd36c7a3561266d198726eefc9f6a11036 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 2 May 2011 18:19:32 -0700 Subject: [PATCH] cfuse: encode/decode dev_t properly The fuse layer passes through "encoded" dev_t values (probably for compatibility reasons or something). I copied the encode/decode methods from the kernel and encode/decode the st_rdev values where appropriate (where struct stat is exposed directory or via the fuse_entry_param struct). Fixes: #1031 Signed-off-by: Sage Weil --- src/client/fuse_ll.cc | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index 0844d9708492b..39567ef06a623 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -73,6 +73,28 @@ static uint64_t make_fake_ino(inodeno_t ino, snapid_t snapid) return fino; } +#define MINORBITS 20 +#define MINORMASK ((1U << MINORBITS) - 1) + +#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) +#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) +#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) + +static uint32_t new_encode_dev(dev_t dev) +{ + unsigned major = MAJOR(dev); + unsigned minor = MINOR(dev); + return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); +} + +static dev_t new_decode_dev(uint32_t dev) +{ + unsigned major = (dev & 0xfff00) >> 8; + unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00); + return MKDEV(major, minor); +} + + static void ceph_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { const struct fuse_ctx *ctx = fuse_req_ctx(req); @@ -83,6 +105,7 @@ static void ceph_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) r = client->ll_lookup(fino_vino(parent), name, &fe.attr, ctx->uid, ctx->gid); if (r >= 0) { fe.ino = make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); + fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); @@ -105,6 +128,7 @@ static void ceph_ll_getattr(fuse_req_t req, fuse_ino_t ino, if (client->ll_getattr(fino_vino(ino), &stbuf, ctx->uid, ctx->gid) == 0) { stbuf.st_ino = make_fake_ino(stbuf.st_ino, stbuf.st_dev); + stbuf.st_rdev = new_encode_dev(stbuf.st_rdev); fuse_reply_attr(req, &stbuf, 0); } else fuse_reply_err(req, ENOENT); @@ -207,9 +231,10 @@ static void ceph_ll_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, struct fuse_entry_param fe; memset(&fe, 0, sizeof(fe)); - int r = client->ll_mknod(fino_vino(parent), name, mode, rdev, &fe.attr, ctx->uid, ctx->gid); + int r = client->ll_mknod(fino_vino(parent), name, mode, new_decode_dev(rdev), &fe.attr, ctx->uid, ctx->gid); if (r == 0) { fe.ino = make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); + fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); @@ -226,6 +251,7 @@ static void ceph_ll_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, int r = client->ll_mkdir(fino_vino(parent), name, mode, &fe.attr, ctx->uid, ctx->gid); if (r == 0) { fe.ino = make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); + fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); @@ -255,6 +281,7 @@ static void ceph_ll_symlink(fuse_req_t req, const char *existing, fuse_ino_t par int r = client->ll_symlink(fino_vino(parent), name, existing, &fe.attr, ctx->uid, ctx->gid); if (r == 0) { fe.ino = make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); + fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); @@ -279,6 +306,7 @@ static void ceph_ll_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, int r = client->ll_link(fino_vino(ino), fino_vino(newparent), newname, &fe.attr, ctx->uid, ctx->gid); if (r == 0) { fe.ino = make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); + fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); fuse_reply_entry(req, &fe); } else { fuse_reply_err(req, -r); @@ -359,6 +387,7 @@ static int ceph_ll_add_dirent(void *p, struct dirent *de, struct stat *st, int s st->st_ino = make_fake_ino(de->d_ino, c->snap); st->st_mode = DT_TO_MODE(de->d_type); + st->st_rdev = new_encode_dev(st->st_rdev); size_t room = c->size - c->pos; size_t entrysize = fuse_add_direntry(c->req, c->buf + c->pos, room, @@ -512,7 +541,7 @@ int ceph_fuse_ll_main(Client *c, int argc, const char *argv[], int fd) newargv[newargc++] = "-o"; newargv[newargc++] = "default_permissions"; - //newargv[newargc++] = "-d"; + newargv[newargc++] = "-d"; for (int argctr = 1; argctr < argc; argctr++) newargv[newargc++] = argv[argctr]; -- 2.39.5