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);
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);
{
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);
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))
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)
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,
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);
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,
BUG_ON(dentry->d_fsdata);
}
+static int ceph_snapdir_dentry_revalidate(struct dentry *dentry,
+ struct nameidata *nd)
+{
+ return 1; /* FIXME */
+}
+
/*
* reading from a dir
*/
.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 = {
+};
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);
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);
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",
.splice_write = generic_file_splice_write,
.unlocked_ioctl = ceph_ioctl,
};
+
.setxattr = ceph_setxattr,
.getxattr = ceph_getxattr,
.listxattr = ceph_listxattr,
- .removexattr = ceph_removexattr
+ .removexattr = ceph_removexattr,
};
const struct inode_operations ceph_special_iops = {
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);
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;
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;
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);
{
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;
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;
/* 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);
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;
}