github.com/cs3org/reva/v2@v2.27.7/pkg/storage/fs/cephfs/cephfs.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  //go:build ceph
    20  // +build ceph
    21  
    22  package cephfs
    23  
    24  import (
    25  	"context"
    26  	"fmt"
    27  	"io"
    28  	"net/url"
    29  	"os"
    30  	"path/filepath"
    31  	"strconv"
    32  	"strings"
    33  
    34  	cephfs2 "github.com/ceph/go-ceph/cephfs"
    35  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    36  	"github.com/mitchellh/mapstructure"
    37  	"github.com/pkg/errors"
    38  	"github.com/rs/zerolog"
    39  
    40  	"github.com/cs3org/reva/v2/pkg/appctx"
    41  	"github.com/cs3org/reva/v2/pkg/errtypes"
    42  	"github.com/cs3org/reva/v2/pkg/events"
    43  	"github.com/cs3org/reva/v2/pkg/storage"
    44  	"github.com/cs3org/reva/v2/pkg/storage/fs/registry"
    45  )
    46  
    47  const (
    48  	xattrTrustedNs = "trusted."
    49  	xattrEID       = xattrTrustedNs + "eid"
    50  	xattrMd5       = xattrTrustedNs + "checksum"
    51  	xattrMd5ts     = xattrTrustedNs + "checksumTS"
    52  	xattrRef       = xattrTrustedNs + "ref"
    53  	xattrUserNs    = "user."
    54  	snap           = ".snap"
    55  )
    56  
    57  type cephfs struct {
    58  	conf         *Options
    59  	conn         *connections
    60  	adminConn    *adminConn
    61  	chunkHandler *ChunkHandler
    62  }
    63  
    64  func init() {
    65  	registry.Register("cephfs", New)
    66  }
    67  
    68  // New returns an implementation to of the storage.FS interface that talk to
    69  // a ceph filesystem.
    70  func New(m map[string]interface{}, _ events.Stream, _ *zerolog.Logger) (fs storage.FS, err error) {
    71  	c := &Options{}
    72  	if err = mapstructure.Decode(m, c); err != nil {
    73  		return nil, errors.Wrap(err, "error decoding conf")
    74  	}
    75  
    76  	c.fillDefaults()
    77  
    78  	var cache *connections
    79  	if cache, err = newCache(); err != nil {
    80  		return nil, errors.New("cephfs: can't create caches")
    81  	}
    82  
    83  	adminConn := newAdminConn(c.IndexPool)
    84  	if adminConn == nil {
    85  		return nil, errors.Wrap(err, "cephfs: Couldn't create admin connections")
    86  	}
    87  
    88  	for _, dir := range []string{c.ShadowFolder, c.UploadFolder} {
    89  		err = adminConn.adminMount.MakeDir(dir, dirPermFull)
    90  		if err != nil && err.Error() != errFileExists {
    91  			return nil, errors.New("cephfs: can't initialise system dir " + dir + ":" + err.Error())
    92  		}
    93  	}
    94  
    95  	return &cephfs{
    96  		conf:      c,
    97  		conn:      cache,
    98  		adminConn: adminConn,
    99  	}, nil
   100  }
   101  
   102  func (fs *cephfs) GetHome(ctx context.Context) (string, error) {
   103  	if fs.conf.DisableHome {
   104  		return "", errtypes.NotSupported("cephfs: GetHome() home supported disabled")
   105  	}
   106  
   107  	user := fs.makeUser(ctx)
   108  
   109  	return user.home, nil
   110  }
   111  
   112  func (fs *cephfs) CreateHome(ctx context.Context) (err error) {
   113  	if fs.conf.DisableHome {
   114  		return errtypes.NotSupported("cephfs: GetHome() home supported disabled")
   115  	}
   116  
   117  	user := fs.makeUser(ctx)
   118  
   119  	// Stop createhome from running the whole thing because it is called multiple times
   120  	if _, err = fs.adminConn.adminMount.Statx(user.home, cephfs2.StatxMode, 0); err == nil {
   121  		return
   122  	}
   123  
   124  	err = walkPath(user.home, func(path string) error {
   125  		return fs.adminConn.adminMount.MakeDir(path, dirPermDefault)
   126  	}, false)
   127  	if err != nil {
   128  		return getRevaError(err)
   129  	}
   130  
   131  	err = fs.adminConn.adminMount.Chown(user.home, uint32(user.UidNumber), uint32(user.GidNumber))
   132  	if err != nil {
   133  		return getRevaError(err)
   134  	}
   135  
   136  	err = fs.adminConn.adminMount.SetXattr(user.home, "ceph.quota.max_bytes", []byte(fmt.Sprint(fs.conf.UserQuotaBytes)), 0)
   137  	if err != nil {
   138  		return getRevaError(err)
   139  	}
   140  
   141  	user.op(func(cv *cacheVal) {
   142  		err = cv.mount.MakeDir(removeLeadingSlash(fs.conf.ShareFolder), dirPermDefault)
   143  		if err != nil && err.Error() == errFileExists {
   144  			err = nil
   145  		}
   146  	})
   147  
   148  	return getRevaError(err)
   149  }
   150  
   151  func (fs *cephfs) CreateDir(ctx context.Context, ref *provider.Reference) error {
   152  	user := fs.makeUser(ctx)
   153  	path, err := user.resolveRef(ref)
   154  	if err != nil {
   155  		return getRevaError(err)
   156  	}
   157  
   158  	user.op(func(cv *cacheVal) {
   159  		if err = cv.mount.MakeDir(path, dirPermDefault); err != nil {
   160  			return
   161  		}
   162  
   163  		//TODO(tmourati): Add entry id logic
   164  	})
   165  
   166  	return getRevaError(err)
   167  }
   168  
   169  // TouchFile as defined in the storage.FS interface
   170  func (fs *cephfs) TouchFile(ctx context.Context, ref *provider.Reference, markprocessing bool, mtime string) error {
   171  	return fmt.Errorf("unimplemented: TouchFile")
   172  }
   173  
   174  func (fs *cephfs) Delete(ctx context.Context, ref *provider.Reference) (err error) {
   175  	var path string
   176  	user := fs.makeUser(ctx)
   177  	path, err = user.resolveRef(ref)
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	user.op(func(cv *cacheVal) {
   183  		if err = cv.mount.Unlink(path); err != nil && err.Error() == errIsADirectory {
   184  			err = cv.mount.RemoveDir(path)
   185  		}
   186  
   187  		//TODO(tmourati): Add entry id logic
   188  	})
   189  
   190  	//has already been deleted by direct mount
   191  	if err != nil && err.Error() == errNotFound {
   192  		return nil
   193  	}
   194  
   195  	return getRevaError(err)
   196  }
   197  
   198  func (fs *cephfs) Move(ctx context.Context, oldRef, newRef *provider.Reference) (err error) {
   199  	var oldPath, newPath string
   200  	user := fs.makeUser(ctx)
   201  	if oldPath, err = user.resolveRef(oldRef); err != nil {
   202  		return
   203  	}
   204  	if newPath, err = user.resolveRef(newRef); err != nil {
   205  		return
   206  	}
   207  
   208  	user.op(func(cv *cacheVal) {
   209  		if err = cv.mount.Rename(oldPath, newPath); err != nil {
   210  			return
   211  		}
   212  
   213  		//TODO(tmourati): Add entry id logic, handle already moved file error
   214  	})
   215  
   216  	// has already been moved by direct mount
   217  	if err != nil && err.Error() == errNotFound {
   218  		return nil
   219  	}
   220  
   221  	return getRevaError(err)
   222  }
   223  
   224  func (fs *cephfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []string, fieldMask []string) (ri *provider.ResourceInfo, err error) {
   225  	var path string
   226  	user := fs.makeUser(ctx)
   227  
   228  	if path, err = user.resolveRef(ref); err != nil {
   229  		return nil, err
   230  	}
   231  
   232  	user.op(func(cv *cacheVal) {
   233  		var stat Statx
   234  		if stat, err = cv.mount.Statx(path, cephfs2.StatxBasicStats, 0); err != nil {
   235  			return
   236  		}
   237  		ri, err = user.fileAsResourceInfo(cv, path, stat, mdKeys)
   238  	})
   239  
   240  	return ri, getRevaError(err)
   241  }
   242  
   243  func (fs *cephfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys []string, fieldMask []string) (files []*provider.ResourceInfo, err error) {
   244  	var path string
   245  	user := fs.makeUser(ctx)
   246  	if path, err = user.resolveRef(ref); err != nil {
   247  		return
   248  	}
   249  
   250  	user.op(func(cv *cacheVal) {
   251  		var dir *cephfs2.Directory
   252  		if dir, err = cv.mount.OpenDir(path); err != nil {
   253  			return
   254  		}
   255  		defer closeDir(dir)
   256  
   257  		var entry *cephfs2.DirEntryPlus
   258  		var ri *provider.ResourceInfo
   259  		for entry, err = dir.ReadDirPlus(cephfs2.StatxBasicStats, 0); entry != nil && err == nil; entry, err = dir.ReadDirPlus(cephfs2.StatxBasicStats, 0) {
   260  			if fs.conf.HiddenDirs[entry.Name()] {
   261  				continue
   262  			}
   263  
   264  			ri, err = user.fileAsResourceInfo(cv, filepath.Join(path, entry.Name()), entry.Statx(), mdKeys)
   265  			if ri == nil || err != nil {
   266  				if err != nil {
   267  					log := appctx.GetLogger(ctx)
   268  					log.Err(err).Msg("cephfs: error in file as resource info")
   269  				}
   270  				err = nil
   271  				continue
   272  			}
   273  
   274  			files = append(files, ri)
   275  		}
   276  	})
   277  
   278  	return files, getRevaError(err)
   279  }
   280  
   281  func (fs *cephfs) Download(ctx context.Context, ref *provider.Reference, openReaderFunc func(md *provider.ResourceInfo) bool) (ri *provider.ResourceInfo, rc io.ReadCloser, err error) {
   282  	var path string
   283  	user := fs.makeUser(ctx)
   284  	if path, err = user.resolveRef(ref); err != nil {
   285  		return nil, nil, errors.Wrap(err, "cephfs: error resolving ref")
   286  	}
   287  
   288  	user.op(func(cv *cacheVal) {
   289  		if strings.HasPrefix(strings.TrimPrefix(path, user.home), fs.conf.ShareFolder) {
   290  			err = errtypes.PermissionDenied("cephfs: cannot download under the virtual share folder")
   291  			return
   292  		}
   293  
   294  		var stat Statx
   295  		if stat, err = cv.mount.Statx(path, cephfs2.StatxBasicStats, 0); err != nil {
   296  			return
   297  		}
   298  		ri, err = user.fileAsResourceInfo(cv, path, stat, nil)
   299  		if err != nil {
   300  			return
   301  		}
   302  
   303  		if !openReaderFunc(ri) {
   304  			return
   305  		}
   306  
   307  		rc, err = cv.mount.Open(path, os.O_RDONLY, 0)
   308  	})
   309  
   310  	return ri, rc, getRevaError(err)
   311  }
   312  
   313  func (fs *cephfs) ListRevisions(ctx context.Context, ref *provider.Reference) (fvs []*provider.FileVersion, err error) {
   314  	//TODO(tmourati): Fix entry id logic
   315  	var path string
   316  	user := fs.makeUser(ctx)
   317  	if path, err = user.resolveRef(ref); err != nil {
   318  		return nil, errors.Wrap(err, "cephfs: error resolving ref")
   319  	}
   320  
   321  	user.op(func(cv *cacheVal) {
   322  		if strings.HasPrefix(path, removeLeadingSlash(fs.conf.ShareFolder)) {
   323  			err = errtypes.PermissionDenied("cephfs: cannot download under the virtual share folder")
   324  			return
   325  		}
   326  		var dir *cephfs2.Directory
   327  		if dir, err = cv.mount.OpenDir(".snap"); err != nil {
   328  			return
   329  		}
   330  		defer closeDir(dir)
   331  
   332  		for d, _ := dir.ReadDir(); d != nil; d, _ = dir.ReadDir() {
   333  			var revPath string
   334  			var stat Statx
   335  			var e error
   336  
   337  			if strings.HasPrefix(d.Name(), ".") {
   338  				continue
   339  			}
   340  
   341  			revPath, e = resolveRevRef(cv.mount, ref, d.Name())
   342  			if e != nil {
   343  				continue
   344  			}
   345  			stat, e = cv.mount.Statx(revPath, cephfs2.StatxMtime|cephfs2.StatxSize, 0)
   346  			if e != nil {
   347  				continue
   348  			}
   349  			fvs = append(fvs, &provider.FileVersion{
   350  				Key:   d.Name(),
   351  				Size:  stat.Size,
   352  				Mtime: uint64(stat.Mtime.Sec),
   353  			})
   354  		}
   355  	})
   356  
   357  	return fvs, getRevaError(err)
   358  }
   359  
   360  func (fs *cephfs) DownloadRevision(ctx context.Context, ref *provider.Reference, key string, openReaderFunc func(md *provider.ResourceInfo) bool) (ri *provider.ResourceInfo, file io.ReadCloser, err error) {
   361  	//TODO(tmourati): Fix entry id logic
   362  	user := fs.makeUser(ctx)
   363  
   364  	user.op(func(cv *cacheVal) {
   365  		var revPath string
   366  		revPath, err = resolveRevRef(cv.mount, ref, key)
   367  		if err != nil {
   368  			return
   369  		}
   370  
   371  		var stat Statx
   372  		stat, err = cv.mount.Statx(revPath, cephfs2.StatxMtime|cephfs2.StatxSize, 0)
   373  		if err != nil {
   374  			return
   375  		}
   376  		ri, err = user.fileAsResourceInfo(cv, revPath, stat, nil)
   377  		if err != nil {
   378  			return
   379  		}
   380  		if !openReaderFunc(ri) {
   381  			return
   382  		}
   383  		file, err = cv.mount.Open(revPath, os.O_RDONLY, 0)
   384  	})
   385  
   386  	return ri, file, getRevaError(err)
   387  }
   388  
   389  func (fs *cephfs) RestoreRevision(ctx context.Context, ref *provider.Reference, key string) (err error) {
   390  	//TODO(tmourati): Fix entry id logic
   391  	var path string
   392  	user := fs.makeUser(ctx)
   393  	if path, err = user.resolveRef(ref); err != nil {
   394  		return errors.Wrap(err, "cephfs: error resolving ref")
   395  	}
   396  
   397  	user.op(func(cv *cacheVal) {
   398  		var revPath string
   399  		if revPath, err = resolveRevRef(cv.mount, ref, key); err != nil {
   400  			err = errors.Wrap(err, "cephfs: error resolving revision ref "+ref.String())
   401  			return
   402  		}
   403  
   404  		var src, dst *cephfs2.File
   405  		if src, err = cv.mount.Open(revPath, os.O_RDONLY, 0); err != nil {
   406  			return
   407  		}
   408  		defer closeFile(src)
   409  
   410  		if dst, err = cv.mount.Open(path, os.O_WRONLY|os.O_TRUNC, 0); err != nil {
   411  			return
   412  		}
   413  		defer closeFile(dst)
   414  
   415  		_, err = io.Copy(dst, src)
   416  	})
   417  
   418  	return getRevaError(err)
   419  }
   420  
   421  func (fs *cephfs) GetPathByID(ctx context.Context, id *provider.ResourceId) (str string, err error) {
   422  	//TODO(tmourati): Add entry id logic
   423  	return "", errtypes.NotSupported("cephfs: entry IDs currently not supported")
   424  }
   425  
   426  func (fs *cephfs) AddGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) (err error) {
   427  	var path string
   428  	user := fs.makeUser(ctx)
   429  	if path, err = user.resolveRef(ref); err != nil {
   430  		return
   431  	}
   432  
   433  	user.op(func(cv *cacheVal) {
   434  		err = fs.changePerms(ctx, cv.mount, g, path, updateGrant)
   435  	})
   436  
   437  	return getRevaError(err)
   438  }
   439  
   440  func (fs *cephfs) RemoveGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) (err error) {
   441  	var path string
   442  	user := fs.makeUser(ctx)
   443  	if path, err = user.resolveRef(ref); err != nil {
   444  		return
   445  	}
   446  
   447  	user.op(func(cv *cacheVal) {
   448  		err = fs.changePerms(ctx, cv.mount, g, path, removeGrant)
   449  	})
   450  
   451  	return getRevaError(err)
   452  }
   453  
   454  func (fs *cephfs) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) (err error) {
   455  	var path string
   456  	user := fs.makeUser(ctx)
   457  	if path, err = user.resolveRef(ref); err != nil {
   458  		return
   459  	}
   460  
   461  	user.op(func(cv *cacheVal) {
   462  		err = fs.changePerms(ctx, cv.mount, g, path, updateGrant)
   463  	})
   464  
   465  	return getRevaError(err)
   466  }
   467  
   468  func (fs *cephfs) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) (err error) {
   469  	var path string
   470  	user := fs.makeUser(ctx)
   471  	if path, err = user.resolveRef(ref); err != nil {
   472  		return
   473  	}
   474  
   475  	user.op(func(cv *cacheVal) {
   476  		grant := &provider.Grant{Grantee: g} //nil perms will remove the whole grant
   477  		err = fs.changePerms(ctx, cv.mount, grant, path, removeGrant)
   478  	})
   479  
   480  	return getRevaError(err)
   481  }
   482  
   483  func (fs *cephfs) ListGrants(ctx context.Context, ref *provider.Reference) (glist []*provider.Grant, err error) {
   484  	var path string
   485  	user := fs.makeUser(ctx)
   486  	if path, err = user.resolveRef(ref); err != nil {
   487  		return
   488  	}
   489  
   490  	user.op(func(cv *cacheVal) {
   491  		glist = fs.getFullPermissionSet(ctx, cv.mount, path)
   492  
   493  		if glist == nil {
   494  			err = errors.New("cephfs: error listing grants on " + path)
   495  		}
   496  	})
   497  
   498  	return glist, getRevaError(err)
   499  }
   500  
   501  func (fs *cephfs) GetQuota(ctx context.Context, ref *provider.Reference) (total uint64, used uint64, remaining uint64, err error) {
   502  	user := fs.makeUser(ctx)
   503  
   504  	log := appctx.GetLogger(ctx)
   505  	user.op(func(cv *cacheVal) {
   506  		var buf []byte
   507  		buf, err = cv.mount.GetXattr(".", "ceph.quota.max_bytes")
   508  		if err != nil {
   509  			log.Warn().Msg("cephfs: user quota bytes not set")
   510  			total = fs.conf.UserQuotaBytes
   511  		} else {
   512  			total, _ = strconv.ParseUint(string(buf), 10, 64)
   513  		}
   514  
   515  		buf, err = cv.mount.GetXattr(".", "ceph.dir.rbytes")
   516  		if err == nil {
   517  			used, err = strconv.ParseUint(string(buf), 10, 64)
   518  		}
   519  	})
   520  
   521  	if used >= total {
   522  		remaining = 0
   523  	} else {
   524  		remaining = total - used
   525  	}
   526  
   527  	return total, used, remaining, getRevaError(err)
   528  }
   529  
   530  func (fs *cephfs) CreateReference(ctx context.Context, path string, targetURI *url.URL) (err error) {
   531  	user := fs.makeUser(ctx)
   532  
   533  	user.op(func(cv *cacheVal) {
   534  		if !strings.HasPrefix(strings.TrimPrefix(path, user.home), fs.conf.ShareFolder) {
   535  			err = errors.New("cephfs: can't create reference outside a share folder")
   536  		} else {
   537  			err = cv.mount.MakeDir(path, dirPermDefault)
   538  		}
   539  	})
   540  	if err != nil {
   541  		return getRevaError(err)
   542  	}
   543  
   544  	user.op(func(cv *cacheVal) {
   545  		err = cv.mount.SetXattr(path, xattrRef, []byte(targetURI.String()), 0)
   546  	})
   547  
   548  	return getRevaError(err)
   549  }
   550  
   551  func (fs *cephfs) Shutdown(ctx context.Context) (err error) {
   552  	ctx.Done()
   553  	fs.conn.clearCache()
   554  	_ = fs.adminConn.adminMount.Unmount()
   555  	_ = fs.adminConn.adminMount.Release()
   556  	fs.adminConn.radosConn.Shutdown()
   557  
   558  	return
   559  }
   560  
   561  func (fs *cephfs) SetArbitraryMetadata(ctx context.Context, ref *provider.Reference, md *provider.ArbitraryMetadata) (err error) {
   562  	var path string
   563  	user := fs.makeUser(ctx)
   564  	if path, err = user.resolveRef(ref); err != nil {
   565  		return err
   566  	}
   567  
   568  	user.op(func(cv *cacheVal) {
   569  		for k, v := range md.Metadata {
   570  			if !strings.HasPrefix(k, xattrUserNs) {
   571  				k = xattrUserNs + k
   572  			}
   573  			if e := cv.mount.SetXattr(path, k, []byte(v), 0); e != nil {
   574  				err = errors.Wrap(err, e.Error())
   575  				return
   576  			}
   577  		}
   578  	})
   579  
   580  	return getRevaError(err)
   581  }
   582  
   583  func (fs *cephfs) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Reference, keys []string) (err error) {
   584  	var path string
   585  	user := fs.makeUser(ctx)
   586  	if path, err = user.resolveRef(ref); err != nil {
   587  		return err
   588  	}
   589  
   590  	user.op(func(cv *cacheVal) {
   591  		for _, key := range keys {
   592  			if !strings.HasPrefix(key, xattrUserNs) {
   593  				key = xattrUserNs + key
   594  			}
   595  			if e := cv.mount.RemoveXattr(path, key); e != nil {
   596  				err = errors.Wrap(err, e.Error())
   597  				return
   598  			}
   599  		}
   600  	})
   601  
   602  	return getRevaError(err)
   603  }
   604  
   605  func (fs *cephfs) EmptyRecycle(ctx context.Context, ref *provider.Reference) error {
   606  	return errtypes.NotSupported("cephfs: empty recycle not supported")
   607  }
   608  
   609  func (fs *cephfs) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (r *provider.CreateStorageSpaceResponse, err error) {
   610  	return nil, errors.New("cephfs: createStorageSpace not supported")
   611  }
   612  
   613  func (fs *cephfs) ListRecycle(ctx context.Context, ref *provider.Reference, key, relativePath string) ([]*provider.RecycleItem, error) {
   614  	panic("implement me")
   615  }
   616  
   617  func (fs *cephfs) RestoreRecycleItem(ctx context.Context, ref *provider.Reference, key, relativePath string, restoreRef *provider.Reference) error {
   618  	return errors.New("cephfs: restoreRecycleItem not supported")
   619  }
   620  
   621  func (fs *cephfs) PurgeRecycleItem(ctx context.Context, ref *provider.Reference, key, relativePath string) error {
   622  	return errors.New("cephfs: purgeRecycleItem not supported")
   623  }
   624  
   625  func (fs *cephfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter, unrestricted bool) ([]*provider.StorageSpace, error) {
   626  	return nil, errors.New("cephfs: listStorageSpaces not supported")
   627  }
   628  
   629  func (fs *cephfs) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) {
   630  	return nil, errors.New("cephfs: updateStorageSpace not supported")
   631  }
   632  
   633  func (fs *cephfs) DeleteStorageSpace(ctx context.Context, req *provider.DeleteStorageSpaceRequest) error {
   634  	return errors.New("cephfs: deleteStorageSpace not supported")
   635  }
   636  
   637  // GetLock returns an existing lock on the given reference
   638  func (fs *cephfs) GetLock(ctx context.Context, ref *provider.Reference) (*provider.Lock, error) {
   639  	return nil, errtypes.NotSupported("unimplemented")
   640  }
   641  
   642  // SetLock puts a lock on the given reference
   643  func (fs *cephfs) SetLock(ctx context.Context, ref *provider.Reference, lock *provider.Lock) error {
   644  	return errtypes.NotSupported("unimplemented")
   645  }
   646  
   647  // RefreshLock refreshes an existing lock on the given reference
   648  func (fs *cephfs) RefreshLock(ctx context.Context, ref *provider.Reference, lock *provider.Lock, existingLockID string) error {
   649  	return errtypes.NotSupported("unimplemented")
   650  }
   651  
   652  // Unlock removes an existing lock from the given reference
   653  func (fs *cephfs) Unlock(ctx context.Context, ref *provider.Reference, lock *provider.Lock) error {
   654  	return errtypes.NotSupported("unimplemented")
   655  }