]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: Make ll_create use _create
authorSam Lang <sam.lang@inktank.com>
Mon, 17 Dec 2012 19:54:23 +0000 (09:54 -1000)
committerSage Weil <sage@inktank.com>
Fri, 28 Dec 2012 23:10:02 +0000 (15:10 -0800)
This is a fix for bug #3625, where multiple clients race to create a
file, and the loser returns EEXIST instead of a valid file handle.
The patch modifies ll_create in the Client class to use _create(),
which sends the request to the MDS (where an atomic create/open is
performed).

Signed-off-by: Sam Lang <sam.lang@inktank.com>
src/client/Client.cc

index 428ca7aa33b00f2bdf11f141e5ae662be721be6e..060b20eeae1890833cb9b9f81618802e917bdfb8 100644 (file)
@@ -7132,7 +7132,7 @@ int Client::ll_open(vinodeno_t vino, int flags, Fh **fhp, int uid, int gid)
   return r;
 }
 
-int Client::ll_create(vinodeno_t parent, const char *name, mode_t mode, int flags, 
+int Client::ll_create(vinodeno_t parent, const char *name, mode_t mode, int flags,
                      struct stat *attr, Fh **fhp, int uid, int gid)
 {
   Mutex::Locker lock(client_lock);
@@ -7143,26 +7143,51 @@ int Client::ll_create(vinodeno_t parent, const char *name, mode_t mode, int flag
   tout(cct) << mode << std::endl;
   tout(cct) << flags << std::endl;
 
+  bool created = false;
+  Inode *in = NULL;
   Inode *dir = _ll_get_inode(parent);
-  int r = _mknod(dir, name, mode, 0, uid, gid);
+  int r = _lookup(dir, name, &in);
+  if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL))
+    return -EEXIST;
+  if (r == -ENOENT && (flags & O_CREAT)) {
+    created = true;
+    r = _create(dir, name, flags, mode, &in, fhp,
+               0, 0, 0,
+               NULL, uid, gid);
+    if (r < 0)
+      goto out;
+
+    in = (*fhp)->inode;
+  }
+
   if (r < 0)
-    return r;
-  Dentry *dn = dir->dir->dentries[name];
-  Inode *in = dn->inode;
+    goto out;
 
-  r = _open(in, flags, mode, fhp, uid, gid);
-  if (r >= 0) {
-    Inode *in = (*fhp)->inode;
-    fill_stat(in, attr);
-    _ll_get(in);
-  } else {
-    attr->st_ino = 0;
+  assert(in);
+  fill_stat(in, attr);
+  _ll_get(in);
+
+  if (!created) {
+    uid_t uid = geteuid();
+    gid_t gid = getegid();
+    r = check_permissions(in, flags, uid, gid);
+    if (r < 0)
+      goto out;
+
+    r = _open(in, flags, mode, fhp);
+    if (r < 0)
+      goto out;
   }
+
+out:
+  if (r < 0)
+    attr->st_ino = 0;
+
   tout(cct) << (unsigned long)*fhp << std::endl;
   tout(cct) << attr->st_ino << std::endl;
   ldout(cct, 3) << "ll_create " << parent << " " << name << " 0" << oct << mode << dec << " " << flags
          << " = " << r << " (" << *fhp << " " << hex << attr->st_ino << dec << ")" << dendl;
-  return 0;
+  return r;
 }
 
 int Client::ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl)