diff --git a/curvefs/src/client/curve_fuse_op.cpp b/curvefs/src/client/curve_fuse_op.cpp index 672fe7ee93..d99fe96b14 100644 --- a/curvefs/src/client/curve_fuse_op.cpp +++ b/curvefs/src/client/curve_fuse_op.cpp @@ -322,17 +322,21 @@ int Warmup(const std::string& name, const std::string& value) { void FuseOpSetXattr(fuse_req_t req, fuse_ino_t ino, const char* name, const char* value, size_t size, int flags) { - // only support "curvefs.warmup.op" xattr std::string xattrValue(value, size); VLOG(9) << "FuseOpSetXattr" << " ino " << ino << " name " << name << " value " << xattrValue << " flags " << flags; - int code = ENOTSUP; if (strcmp(name, curvefs::client::common::kCurveFsWarmupXAttr) == 0) { // warmup - code = Warmup(name, xattrValue); + int code = Warmup(name, xattrValue); + fuse_reply_err(req, code); + } else { + // set xattr + CURVEFS_ERROR ret = g_ClientInstance->FuseOpSetXattr(req, ino, name, + value, size, flags); + FuseReplyErrByErrCode(req, ret); } - fuse_reply_err(req, code); + VLOG(9) << "FuseOpSetXattr done"; } diff --git a/curvefs/src/client/fuse_client.cpp b/curvefs/src/client/fuse_client.cpp index b166ae8993..6c3d5c4a4c 100644 --- a/curvefs/src/client/fuse_client.cpp +++ b/curvefs/src/client/fuse_client.cpp @@ -1104,49 +1104,49 @@ CURVEFS_ERROR FuseClient::FuseOpGetXattr(fuse_req_t req, fuse_ino_t ino, } std::string xValue; - // get summary info - if (IsSummaryInfo(name)) { - InodeAttr inodeAttr; - CURVEFS_ERROR ret = inodeManager_->GetInodeAttr(ino, &inodeAttr); - if (ret != CURVEFS_ERROR::OK) { - LOG(ERROR) << "inodeManager get inodeAttr fail, ret = " << ret - << ", inodeid = " << ino; - return ret; - } + InodeAttr inodeAttr; + CURVEFS_ERROR ret = inodeManager_->GetInodeAttr(ino, &inodeAttr); + if (ret != CURVEFS_ERROR::OK) { + LOG(ERROR) << "inodeManager get inodeAttr fail, ret = " << ret + << ", inodeid = " << ino; + return ret; + } - if (inodeAttr.type() == FsFileType::TYPE_DIRECTORY) { - // not enable record summary info in dir xattr, - // need recursive computation all files - if (!enableSumInDir_) { - if (IsOneLayer(name)) { - ret = xattrManager_->CalOneLayerSumInfo(&inodeAttr); - } else { - ret = xattrManager_->CalAllLayerSumInfo(&inodeAttr); - } + // get summary info if the xattr name is summary type + if (IsSummaryInfo(name) && inodeAttr.type() == FsFileType::TYPE_DIRECTORY) { + // if not enable record summary info in dir xattr, + // need recursive computation all files; + // otherwise only recursive computation all dirs. + if (!enableSumInDir_) { + if (IsOneLayer(name)) { + ret = xattrManager_->CalOneLayerSumInfo(&inodeAttr); } else { - if (IsOneLayer(name)) { - ret = xattrManager_->FastCalOneLayerSumInfo(&inodeAttr); - } else { - ret = xattrManager_->FastCalAllLayerSumInfo(&inodeAttr); - } - } - - if (CURVEFS_ERROR::OK != ret) { - return ret; + ret = xattrManager_->CalAllLayerSumInfo(&inodeAttr); } - LOG(INFO) << "After calculate summary info:\n" - << inodeAttr.DebugString(); - auto it = inodeAttr.xattr().find(name); - if (it != inodeAttr.xattr().end()) { - xValue = it->second; + } else { + if (IsOneLayer(name)) { + ret = xattrManager_->FastCalOneLayerSumInfo(&inodeAttr); + } else { + ret = xattrManager_->FastCalAllLayerSumInfo(&inodeAttr); } } + + if (CURVEFS_ERROR::OK != ret) { + return ret; + } + LOG(INFO) << "After calculate summary info:\n" + << inodeAttr.DebugString(); } - CURVEFS_ERROR ret = CURVEFS_ERROR::NODATA; + auto it = inodeAttr.xattr().find(name); + if (it != inodeAttr.xattr().end()) { + xValue = it->second; + } + + ret = CURVEFS_ERROR::NODATA; if (xValue.length() > 0) { if ((size == 0 && xValue.length() <= MAXXATTRLENGTH) || - (size >= xValue.length() && size <= MAXXATTRLENGTH)) { + (size >= xValue.length() && xValue.length() <= MAXXATTRLENGTH)) { memcpy(value, xValue.c_str(), xValue.length()); ret = CURVEFS_ERROR::OK; } else { @@ -1156,6 +1156,43 @@ CURVEFS_ERROR FuseClient::FuseOpGetXattr(fuse_req_t req, fuse_ino_t ino, return ret; } +CURVEFS_ERROR FuseClient::FuseOpSetXattr(fuse_req_t req, fuse_ino_t ino, + const char* name, const char* value, + size_t size, int flags) { + VLOG(1) << "FuseOpSetXattr ino: " << ino << ", name: " << name + << ", value: " << value; + if (option_.disableXattr) { + return CURVEFS_ERROR::NOTSUPPORT; + } + + std::string strname(name); + std::string strvalue(value, size); + if (strname.length() > MAXXATTRLENGTH || size > MAXXATTRLENGTH) { + LOG(ERROR) << "xattr length is too long, name = " << name + << ", name length = " << strname.length() + << ", value length = " << size; + return CURVEFS_ERROR::OUT_OF_RANGE; + } + + std::shared_ptr inodeWrapper; + CURVEFS_ERROR ret = inodeManager_->GetInode(ino, inodeWrapper); + if (ret != CURVEFS_ERROR::OK) { + LOG(ERROR) << "inodeManager get inode fail, ret = " << ret + << ", inodeid = " << ino; + return ret; + } + + ::curve::common::UniqueLock lgGuard = inodeWrapper->GetUniqueLock(); + inodeWrapper->SetXattrLocked(strname, strvalue); + ret = inodeWrapper->SyncAttr(); + if (ret != CURVEFS_ERROR::OK) { + LOG(ERROR) << "set xattr fail, ret = " << ret << ", inodeid = " << ino + << ", name = " << strname << ", value = " << strvalue; + return ret; + } + return CURVEFS_ERROR::OK; +} + CURVEFS_ERROR FuseClient::FuseOpListXattr(fuse_req_t req, fuse_ino_t ino, char *value, size_t size, size_t *realSize) { VLOG(1) << "FuseOpListXattr, ino: " << ino << ", size = " << size; diff --git a/curvefs/src/client/fuse_client.h b/curvefs/src/client/fuse_client.h index 28bb31295c..3a3743bb48 100644 --- a/curvefs/src/client/fuse_client.h +++ b/curvefs/src/client/fuse_client.h @@ -194,6 +194,10 @@ class FuseClient { const char* name, void* value, size_t size); + virtual CURVEFS_ERROR FuseOpSetXattr(fuse_req_t req, fuse_ino_t ino, + const char* name, const char* value, + size_t size, int flags); + virtual CURVEFS_ERROR FuseOpListXattr(fuse_req_t req, fuse_ino_t ino, char *value, size_t size, size_t *realSize); diff --git a/curvefs/src/client/inode_wrapper.h b/curvefs/src/client/inode_wrapper.h index e832bdc101..82342bdd05 100644 --- a/curvefs/src/client/inode_wrapper.h +++ b/curvefs/src/client/inode_wrapper.h @@ -199,6 +199,12 @@ class InodeWrapper : public std::enable_shared_from_this { return ret; } + void SetXattrLocked(const std::string &key, const std::string &value) { + (*inode_.mutable_xattr())[key] = value; + (*dirtyAttr_.mutable_xattr()) = inode_.xattr(); + dirty_ = true; + } + curve::common::UniqueLock GetUniqueLock() { return curve::common::UniqueLock(mtx_); } diff --git a/curvefs/test/client/test_fuse_client.cpp b/curvefs/test/client/test_fuse_client.cpp index 3823dcccb4..386cc04f2c 100644 --- a/curvefs/test/client/test_fuse_client.cpp +++ b/curvefs/test/client/test_fuse_client.cpp @@ -3484,5 +3484,58 @@ TEST_F(TestFuseS3Client, FuseOpListXattr) { ASSERT_EQ(CURVEFS_ERROR::OK, ret); } +TEST_F(TestFuseS3Client, FuseOpSetXattr_TooLong) { + // in + fuse_req_t req; + fuse_ino_t ino = 1; + const char name[] = "security.selinux"; + size_t size = 300; + char value[300]; + std::memset(value, 0, 300); + + CURVEFS_ERROR ret = client_->FuseOpSetXattr( + req, ino, name, value, size, 0); + ASSERT_EQ(CURVEFS_ERROR::OUT_OF_RANGE, ret); +} + +TEST_F(TestFuseS3Client, FuseOpSetXattr) { + // in + fuse_req_t req; + fuse_ino_t ino = 1; + const char name[] = "security.selinux"; + size_t size = 100; + char value[100]; + std::memset(value, 0, 100); + + // get inode failed + EXPECT_CALL(*inodeManager_, GetInode(ino, _)) + .WillOnce(Return(CURVEFS_ERROR::INTERNAL)); + CURVEFS_ERROR ret = client_->FuseOpSetXattr( + req, ino, name, value, size, 0); + ASSERT_EQ(CURVEFS_ERROR::INTERNAL, ret); + + // updateInode failed + auto inodeWrapper = std::make_shared(Inode(), metaClient_); + EXPECT_CALL(*inodeManager_, GetInode(ino, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(*metaClient_, UpdateInodeAttrWithOutNlink(_, _, _, _, _)) + .WillOnce(Return(MetaStatusCode::NOT_FOUND)); + ret = client_->FuseOpSetXattr( + req, ino, name, value, size, 0); + ASSERT_EQ(CURVEFS_ERROR::NOTEXIST, ret); + + // success + EXPECT_CALL(*inodeManager_, GetInode(ino, _)) + .WillOnce( + DoAll(SetArgReferee<1>(inodeWrapper), Return(CURVEFS_ERROR::OK))); + EXPECT_CALL(*metaClient_, UpdateInodeAttrWithOutNlink(_, _, _, _, _)) + .WillOnce(Return(MetaStatusCode::OK)); + ret = client_->FuseOpSetXattr( + req, ino, name, value, size, 0); + ASSERT_EQ(CURVEFS_ERROR::OK, ret); +} + + } // namespace client } // namespace curvefs diff --git a/curvefs/test/client/test_inodeWrapper.cpp b/curvefs/test/client/test_inodeWrapper.cpp index 0282801bf7..d374e4791b 100644 --- a/curvefs/test/client/test_inodeWrapper.cpp +++ b/curvefs/test/client/test_inodeWrapper.cpp @@ -333,5 +333,13 @@ TEST_F(TestInodeWrapper, TestUpdateInodeAttrIncrementally) { ASSERT_FALSE(wrapper.dirtyAttr_.has_atime_ns()); } +TEST_F(TestInodeWrapper, TestSetXattr) { + inodeWrapper_->SetXattrLocked("name", "value"); + XAttr xattr = inodeWrapper_->GetXattr(); + ASSERT_TRUE(xattr.xattrinfos().find("name") != xattr.xattrinfos().end()); + ASSERT_EQ((*xattr.mutable_xattrinfos())["name"], "value"); + ASSERT_TRUE(inodeWrapper_->IsDirty()); +} + } // namespace client } // namespace curvefs