Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5905a92 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull two Ceph fixes from Sage Weil:
 "One of these is fixing a regression from the d_flags file type patch
  that went into -rc1 that broke instantiation of inodes and dentries
  (we were doing dentries first).  The other is just an off-by-one
  corner case"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client:
  ceph: Avoid data inconsistency due to d-cache aliasing in readpage()
  ceph: initialize inode before instantiating dentry
parents 4ddebaf4 56f91aad
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -210,9 +210,13 @@ static int readpage_nounlock(struct file *filp, struct page *page)
	if (err < 0) {
		SetPageError(page);
		goto out;
	} else if (err < PAGE_CACHE_SIZE) {
	} else {
		if (err < PAGE_CACHE_SIZE) {
		/* zero fill remainder of page */
			zero_user_segment(page, err, PAGE_CACHE_SIZE);
		} else {
			flush_dcache_page(page);
		}
	}
	SetPageUptodate(page);

+58 −78
Original line number Diff line number Diff line
@@ -978,7 +978,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
	struct ceph_mds_reply_inode *ininfo;
	struct ceph_vino vino;
	struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
	int i = 0;
	int err = 0;

	dout("fill_trace %p is_dentry %d is_target %d\n", req,
@@ -1039,6 +1038,29 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
		}
	}

	if (rinfo->head->is_target) {
		vino.ino = le64_to_cpu(rinfo->targeti.in->ino);
		vino.snap = le64_to_cpu(rinfo->targeti.in->snapid);

		in = ceph_get_inode(sb, vino);
		if (IS_ERR(in)) {
			err = PTR_ERR(in);
			goto done;
		}
		req->r_target_inode = in;

		err = fill_inode(in, &rinfo->targeti, NULL,
				session, req->r_request_started,
				(le32_to_cpu(rinfo->head->result) == 0) ?
				req->r_fmode : -1,
				&req->r_caps_reservation);
		if (err < 0) {
			pr_err("fill_inode badness %p %llx.%llx\n",
				in, ceph_vinop(in));
			goto done;
		}
	}

	/*
	 * ignore null lease/binding on snapdir ENOENT, or else we
	 * will have trouble splicing in the virtual snapdir later
@@ -1108,7 +1130,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
			     ceph_dentry(req->r_old_dentry)->offset);

			dn = req->r_old_dentry;  /* use old_dentry */
			in = dn->d_inode;
		}

		/* null dentry? */
@@ -1130,44 +1151,28 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
		}

		/* attach proper inode */
		ininfo = rinfo->targeti.in;
		vino.ino = le64_to_cpu(ininfo->ino);
		vino.snap = le64_to_cpu(ininfo->snapid);
		in = dn->d_inode;
		if (!in) {
			in = ceph_get_inode(sb, vino);
			if (IS_ERR(in)) {
				pr_err("fill_trace bad get_inode "
				       "%llx.%llx\n", vino.ino, vino.snap);
				err = PTR_ERR(in);
				d_drop(dn);
				goto done;
			}
		if (!dn->d_inode) {
			ihold(in);
			dn = splice_dentry(dn, in, &have_lease, true);
			if (IS_ERR(dn)) {
				err = PTR_ERR(dn);
				goto done;
			}
			req->r_dentry = dn;  /* may have spliced */
			ihold(in);
		} else if (ceph_ino(in) == vino.ino &&
			   ceph_snap(in) == vino.snap) {
			ihold(in);
		} else {
		} else if (dn->d_inode && dn->d_inode != in) {
			dout(" %p links to %p %llx.%llx, not %llx.%llx\n",
			     dn, in, ceph_ino(in), ceph_snap(in),
			     vino.ino, vino.snap);
			     dn, dn->d_inode, ceph_vinop(dn->d_inode),
			     ceph_vinop(in));
			have_lease = false;
			in = NULL;
		}

		if (have_lease)
			update_dentry_lease(dn, rinfo->dlease, session,
					    req->r_request_started);
		dout(" final dn %p\n", dn);
		i++;
	} else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
		   req->r_op == CEPH_MDS_OP_MKSNAP) && !req->r_aborted) {
	} else if (!req->r_aborted &&
		   (req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
		    req->r_op == CEPH_MDS_OP_MKSNAP)) {
		struct dentry *dn = req->r_dentry;

		/* fill out a snapdir LOOKUPSNAP dentry */
@@ -1177,52 +1182,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
		ininfo = rinfo->targeti.in;
		vino.ino = le64_to_cpu(ininfo->ino);
		vino.snap = le64_to_cpu(ininfo->snapid);
		in = ceph_get_inode(sb, vino);
		if (IS_ERR(in)) {
			pr_err("fill_inode get_inode badness %llx.%llx\n",
			       vino.ino, vino.snap);
			err = PTR_ERR(in);
			d_delete(dn);
			goto done;
		}
		dout(" linking snapped dir %p to dn %p\n", in, dn);
		ihold(in);
		dn = splice_dentry(dn, in, NULL, true);
		if (IS_ERR(dn)) {
			err = PTR_ERR(dn);
			goto done;
		}
		req->r_dentry = dn;  /* may have spliced */
		ihold(in);
		rinfo->head->is_dentry = 1;  /* fool notrace handlers */
	}

	if (rinfo->head->is_target) {
		vino.ino = le64_to_cpu(rinfo->targeti.in->ino);
		vino.snap = le64_to_cpu(rinfo->targeti.in->snapid);

		if (in == NULL || ceph_ino(in) != vino.ino ||
		    ceph_snap(in) != vino.snap) {
			in = ceph_get_inode(sb, vino);
			if (IS_ERR(in)) {
				err = PTR_ERR(in);
				goto done;
			}
		}
		req->r_target_inode = in;

		err = fill_inode(in,
				 &rinfo->targeti, NULL,
				 session, req->r_request_started,
				 (le32_to_cpu(rinfo->head->result) == 0) ?
				 req->r_fmode : -1,
				 &req->r_caps_reservation);
		if (err < 0) {
			pr_err("fill_inode badness %p %llx.%llx\n",
			       in, ceph_vinop(in));
			goto done;
		}
	}

done:
	dout("fill_trace done err=%d\n", err);
	return err;
@@ -1272,7 +1240,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
	struct qstr dname;
	struct dentry *dn;
	struct inode *in;
	int err = 0, i;
	int err = 0, ret, i;
	struct inode *snapdir = NULL;
	struct ceph_mds_request_head *rhead = req->r_request->front.iov_base;
	struct ceph_dentry_info *di;
@@ -1305,6 +1273,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
			ceph_fill_dirfrag(parent->d_inode, rinfo->dir_dir);
	}

	/* FIXME: release caps/leases if error occurs */
	for (i = 0; i < rinfo->dir_nr; i++) {
		struct ceph_vino vino;

@@ -1329,9 +1298,10 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
				err = -ENOMEM;
				goto out;
			}
			err = ceph_init_dentry(dn);
			if (err < 0) {
			ret = ceph_init_dentry(dn);
			if (ret < 0) {
				dput(dn);
				err = ret;
				goto out;
			}
		} else if (dn->d_inode &&
@@ -1351,9 +1321,6 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
			spin_unlock(&parent->d_lock);
		}

		di = dn->d_fsdata;
		di->offset = ceph_make_fpos(frag, i + r_readdir_offset);

		/* inode */
		if (dn->d_inode) {
			in = dn->d_inode;
@@ -1366,18 +1333,30 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
				err = PTR_ERR(in);
				goto out;
			}
			dn = splice_dentry(dn, in, NULL, false);
			if (IS_ERR(dn))
				dn = NULL;
		}

		if (fill_inode(in, &rinfo->dir_in[i], NULL, session,
			       req->r_request_started, -1,
			       &req->r_caps_reservation) < 0) {
			pr_err("fill_inode badness on %p\n", in);
			if (!dn->d_inode)
				iput(in);
			d_drop(dn);
			goto next_item;
		}
		if (dn)

		if (!dn->d_inode) {
			dn = splice_dentry(dn, in, NULL, false);
			if (IS_ERR(dn)) {
				err = PTR_ERR(dn);
				dn = NULL;
				goto next_item;
			}
		}

		di = dn->d_fsdata;
		di->offset = ceph_make_fpos(frag, i + r_readdir_offset);

		update_dentry_lease(dn, rinfo->dir_dlease[i],
				    req->r_session,
				    req->r_request_started);
@@ -1385,6 +1364,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
		if (dn)
			dput(dn);
	}
	if (err == 0)
		req->r_did_prepopulate = true;

out: