return err;
}
+static int ceph_mksnap(struct inode *dir, struct dentry *dentry)
+{
+ struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ struct ceph_mds_request_head *rhead;
+ char *path;
+ int pathlen;
+ u64 pathbase;
+ int err;
+ char *snap;
+ int snaplen;
+ struct dentry *dirdentry = d_find_alias(dir);
+
+ snaplen = dentry->d_name.len;
+ snap = kmalloc(snaplen + 1, GFP_NOFS);
+ memcpy(snap, dentry->d_name.name, snaplen);
+ snap[snaplen] = 0;
+
+ dout(5, "dir_mksnap in dir %p name '%s' dn %p\n", dir, snap, dentry);
+ path = ceph_build_dentry_path(dirdentry, &pathlen, &pathbase, 1);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_MKSNAP,
+ pathbase, path,
+ 0, snap,
+ dentry, USE_AUTH_MDS);
+ kfree(path);
+ if (IS_ERR(req)) {
+ dout(40, "d_drop %p\n", dentry);
+ d_drop(dentry);
+ return PTR_ERR(req);
+ }
+
+ dget(dentry); /* to match put_request below */
+ req->r_last_dentry = dentry; /* use this dentry in fill_trace */
+ req->r_locked_dir = dir;
+ rhead = req->r_request->front.iov_base;
+ err = ceph_mdsc_do_request(mdsc, req);
+ ceph_mdsc_put_request(req);
+ if (err < 0) {
+ dout(40, "d_drop %p\n", dentry);
+ d_drop(dentry);
+ }
+ return err;
+
+}
+
static int ceph_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
u64 pathbase;
int err;
+ if (ceph_vino(dir).snap == CEPH_SNAPDIR)
+ return ceph_mksnap(dir, dentry);
+
dout(5, "dir_mkdir in dir %p dentry %p mode 0%o\n", dir, dentry, mode);
path = ceph_build_dentry_path(dentry, &pathlen, &pathbase, 1);
if (IS_ERR(path))