]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
kclient: EROFS in snapdir, snapped dirs
authorSage Weil <sage@newdream.net>
Tue, 12 Aug 2008 16:16:36 +0000 (09:16 -0700)
committerSage Weil <sage@newdream.net>
Tue, 12 Aug 2008 16:16:36 +0000 (09:16 -0700)
src/kernel/dir.c
src/kernel/file.c
src/kernel/inode.c
src/kernel/super.h

index e49993907dfe84d993b87f3816b14b0ef1ae1ecf..0f293d81503f892115925bd23a9abbb1ab2affc4 100644 (file)
@@ -271,11 +271,11 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
                                  struct dentry *dentry, int err)
 {
        struct ceph_client *client = ceph_client(dentry->d_sb);
+       struct inode *parent = dentry->d_parent->d_inode;
 
        /* snap dir? */
        if (err == -ENOENT &&
            strcmp(dentry->d_name.name, client->mount_args.snapdir_name) == 0) {
-               struct inode *parent = dentry->d_parent->d_inode;
                struct inode *inode = ceph_get_snapdir(parent);
                dout(10, "ENOENT on snapdir %p '%.*s', linking to snapdir %p\n",
                     dentry, dentry->d_name.len, dentry->d_name.name, inode);
@@ -392,6 +392,9 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
        u64 pathbase;
        int err;
 
+       if (ceph_vino(dir).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        dout(5, "dir_mknod in dir %p dentry %p mode 0%o rdev %d\n",
             dir, dentry, mode, rdev);
        path = ceph_build_dentry_path(dentry, &pathlen, &pathbase, 1);
@@ -437,6 +440,10 @@ static int ceph_create(struct inode *dir, struct dentry *dentry, int mode,
 {
        dout(5, "create in dir %p dentry %p name '%.*s'\n",
             dir, dentry, dentry->d_name.len, dentry->d_name.name);
+
+       if (ceph_vino(dir).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        if (nd) {
                BUG_ON((nd->flags & LOOKUP_OPEN) == 0);
                dentry = ceph_lookup_open(dir, dentry, nd, mode, 0);
@@ -461,6 +468,9 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
        u64 pathbase;
        int err;
 
+       if (ceph_vino(dir).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        dout(5, "dir_symlink in dir %p dentry %p to '%s'\n", dir, dentry, dest);
        path = ceph_build_dentry_path(dentry, &pathlen, &pathbase, 1);
        if (IS_ERR(path))
@@ -508,7 +518,9 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                snap[snaplen] = 0;
                pathdentry = d_find_alias(dir);
                dout(5, "dir_mksnap dir %p '%s' dn %p\n", dir, snap, dentry);
-       } else
+       } else if (ceph_vino(dir).snap != CEPH_NOSNAP)
+               return -EROFS;
+       else
                dout(5, "dir_mkdir dir %p dn %p mode 0%o\n", dir, dentry, mode);
        path = ceph_build_dentry_path(pathdentry, &pathlen, &pathbase, 1);
        if (pathdentry != dentry)
@@ -552,6 +564,9 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
        u64 oldpathbase, pathbase;
        int err;
 
+       if (ceph_vino(dir).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        dout(5, "dir_link in dir %p old_dentry %p dentry %p\n", dir,
             old_dentry, dentry);
        oldpath = ceph_build_dentry_path(old_dentry, &oldpathlen, &oldpathbase,
@@ -620,7 +635,9 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
                snap[snaplen] = 0;
                pathdentry = d_find_alias(dir);
                dout(5, "dir_rmsnap dir %p '%s' dn %p\n", dir, snap, dentry);
-       } else
+       } else if (ceph_vino(dir).snap != CEPH_NOSNAP)
+               return -EROFS;
+       else
                dout(5, "dir_unlink/rmdir dir %p dn %p inode %p\n",
                     dir, dentry, inode);
        path = ceph_build_dentry_path(pathdentry, &pathlen, &pathbase, 1);
@@ -665,6 +682,12 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
        u64 oldpathbase, newpathbase;
        int err;
 
+       if (ceph_vino(old_dir).snap != ceph_vino(new_dir).snap)
+               return -EXDEV;
+       if (ceph_vino(old_dir).snap != CEPH_NOSNAP ||
+           ceph_vino(new_dir).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        dout(5, "dir_rename in dir %p dentry %p to dir %p dentry %p\n",
             old_dir, old_dentry, new_dir, new_dentry);
        oldpath = ceph_build_dentry_path(old_dentry, &oldpathlen, &oldpathbase,
@@ -748,6 +771,12 @@ static void ceph_dentry_release(struct dentry *dentry)
        BUG_ON(dentry->d_fsdata);
 }
 
+static int ceph_snapdir_dentry_revalidate(struct dentry *dentry,
+                                         struct nameidata *nd)
+{
+       return 1; /* FIXME */
+}
+
 /*
  * reading from a dir
  */
@@ -828,3 +857,9 @@ struct dentry_operations ceph_dentry_ops = {
        .d_release = ceph_dentry_release,
 };
 
+struct dentry_operations ceph_snapdir_dentry_ops = {
+       .d_revalidate = ceph_snapdir_dentry_revalidate,
+};
+
+struct dentry_operations ceph_snap_dentry_ops = {
+};
index 0b634c5a0bb8530af3956d6ed3eb588182abe4f1..544f59e03132c4e98260532f043842b12dc4a78f 100644 (file)
@@ -84,6 +84,9 @@ int ceph_open(struct inode *inode, struct file *file)
        if (S_ISDIR(inode->i_mode))
                flags = O_DIRECTORY;
 
+       if (ceph_vino(inode).snap != CEPH_NOSNAP && (file->f_mode & FMODE_WRITE))
+               return -EROFS;
+
        dout(5, "open inode %p ino %llx.%llx file %p flags %d (%d)\n", inode,
             ceph_vinop(inode), file, flags, file->f_flags);
        fmode = ceph_flags_to_mode(flags);
@@ -229,6 +232,9 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data,
        int ret = 0;
        off_t pos = *offset;
 
+       if (ceph_vino(file->f_dentry->d_inode).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        dout(10, "sync_write on file %p %lld~%u\n", file, *offset,
             (unsigned)count);
 
@@ -326,6 +332,9 @@ ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
        int got = 0;
        int ret;
 
+       if (ceph_vino(inode).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        __ceph_do_pending_vmtruncate(inode);
        check_max_size(inode, endoff);
        dout(10, "aio_write %p %llu~%u getting caps. i_size %llu\n",
@@ -392,3 +401,4 @@ const struct file_operations ceph_file_fops = {
        .splice_write = generic_file_splice_write,
        .unlocked_ioctl = ceph_ioctl,
 };
+
index bed57567fd6e080204f8f2ecd4b1b3a5309c8f60..5a52536e37b4457b8eb78b9e5d73358d0ffaaeb7 100644 (file)
@@ -70,7 +70,7 @@ const struct inode_operations ceph_file_iops = {
        .setxattr = ceph_setxattr,
        .getxattr = ceph_getxattr,
        .listxattr = ceph_listxattr,
-       .removexattr = ceph_removexattr
+       .removexattr = ceph_removexattr,
 };
 
 const struct inode_operations ceph_special_iops = {
@@ -2064,6 +2064,9 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        const unsigned int ia_valid = attr->ia_valid;
        int err;
 
+       if (ceph_vino(inode).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        __ceph_do_pending_vmtruncate(inode);
 
        err = inode_change_ok(inode, attr);
@@ -2314,6 +2317,7 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
                  const void *value, size_t size, int flags)
 {
        struct ceph_client *client = ceph_client(dentry->d_sb);
+       struct inode *inode = dentry->d_inode;
        struct ceph_mds_client *mdsc = &client->mdsc;
        struct ceph_mds_request *req;
        struct ceph_mds_request_head *rhead;
@@ -2325,6 +2329,9 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
        struct page **pages = 0;
        void *kaddr;
 
+       if (ceph_vino(inode).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        /* only support user.* xattrs, for now */
        if (strncmp(name, "user.", 5) != 0)
                return -EOPNOTSUPP;
@@ -2367,7 +2374,7 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
        req->r_request->hdr.data_len = cpu_to_le32(size);
        req->r_request->hdr.data_off = cpu_to_le32(0);
 
-       ceph_mdsc_lease_release(mdsc, dentry->d_inode, 0, CEPH_LOCK_IXATTR);
+       ceph_mdsc_lease_release(mdsc, inode, 0, CEPH_LOCK_IXATTR);
        err = ceph_mdsc_do_request(mdsc, req);
        ceph_mdsc_put_request(req);
 
@@ -2384,12 +2391,16 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
 {
        struct ceph_client *client = ceph_client(dentry->d_sb);
        struct ceph_mds_client *mdsc = &client->mdsc;
+       struct inode *inode = dentry->d_inode;
        struct ceph_mds_request *req;
        char *path;
        int pathlen;
        u64 pathbase;
        int err;
 
+       if (ceph_vino(inode).snap != CEPH_NOSNAP)
+               return -EROFS;
+
        /* only support user.* xattrs, for now */
        if (strncmp(name, "user.", 5) != 0)
                return -EOPNOTSUPP;
@@ -2404,7 +2415,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
        if (IS_ERR(req))
                return PTR_ERR(req);
 
-       ceph_mdsc_lease_release(mdsc, dentry->d_inode, 0, CEPH_LOCK_IXATTR);
+       ceph_mdsc_lease_release(mdsc, inode, 0, CEPH_LOCK_IXATTR);
        err = ceph_mdsc_do_request(mdsc, req);
        ceph_mdsc_put_request(req);
        return err;
index e06694f936f6a1104fd560f2a9b2df73d5e5d6ba..6bd0ba086829a84a371c8dc211448ef9c61ccf7d 100644 (file)
@@ -579,9 +579,10 @@ extern int ceph_release(struct inode *inode, struct file *filp);
 
 
 /* dir.c */
-extern const struct inode_operations ceph_dir_iops;
 extern const struct file_operations ceph_dir_fops;
-extern struct dentry_operations ceph_dentry_ops;
+extern const struct inode_operations ceph_dir_iops;
+extern struct dentry_operations ceph_dentry_ops, ceph_snap_dentry_ops,
+       ceph_snapdir_dentry_ops;
 
 extern char *ceph_build_dentry_path(struct dentry *dn, int *len, __u64 *base,
                                    int min);
@@ -592,7 +593,12 @@ extern struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
                                         struct dentry *dentry, int err);
 
 static inline void ceph_init_dentry(struct dentry *dentry) {
-       dentry->d_op = &ceph_dentry_ops;
+       if (ceph_vino(dentry->d_parent->d_inode).snap == CEPH_NOSNAP)
+               dentry->d_op = &ceph_dentry_ops;
+       else if (ceph_vino(dentry->d_parent->d_inode).snap == CEPH_SNAPDIR)
+               dentry->d_op = &ceph_snapdir_dentry_ops;
+       else
+               dentry->d_op = &ceph_snap_dentry_ops;
        dentry->d_time = 0;
 }