Skip to content

Commit c10a751

Browse files
fllindenTrond Myklebust
authored and
Trond Myklebust
committed
NFSv4.2: add the extended attribute proc functions.
Implement the extended attribute procedures for NFSv4.2 extended attribute support (RFC 8276). Signed-off-by: Frank van der Linden <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent ccde1e9 commit c10a751

File tree

2 files changed

+244
-0
lines changed

2 files changed

+244
-0
lines changed

fs/nfs/nfs42.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ static inline bool nfs42_files_from_same_server(struct file *in,
3939
c_out->cl_serverowner);
4040
}
4141

42+
ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
43+
void *buf, size_t buflen);
44+
int nfs42_proc_setxattr(struct inode *inode, const char *name,
45+
const void *buf, size_t buflen, int flags);
46+
ssize_t nfs42_proc_listxattrs(struct inode *inode, void *buf,
47+
size_t buflen, u64 *cookiep, bool *eofp);
48+
int nfs42_proc_removexattr(struct inode *inode, const char *name);
49+
4250
/*
4351
* Maximum XDR buffer size needed for a listxattr buffer of buflen size.
4452
*

fs/nfs/nfs42proc.c

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,3 +1088,239 @@ int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
10881088
nfs_put_lock_context(src_lock);
10891089
return err;
10901090
}
1091+
1092+
#define NFS4XATTR_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
1093+
1094+
static int _nfs42_proc_removexattr(struct inode *inode, const char *name)
1095+
{
1096+
struct nfs_server *server = NFS_SERVER(inode);
1097+
struct nfs42_removexattrargs args = {
1098+
.fh = NFS_FH(inode),
1099+
.xattr_name = name,
1100+
};
1101+
struct nfs42_removexattrres res;
1102+
struct rpc_message msg = {
1103+
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVEXATTR],
1104+
.rpc_argp = &args,
1105+
.rpc_resp = &res,
1106+
};
1107+
int ret;
1108+
unsigned long timestamp = jiffies;
1109+
1110+
ret = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
1111+
&res.seq_res, 1);
1112+
if (!ret)
1113+
nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0);
1114+
1115+
return ret;
1116+
}
1117+
1118+
static int _nfs42_proc_setxattr(struct inode *inode, const char *name,
1119+
const void *buf, size_t buflen, int flags)
1120+
{
1121+
struct nfs_server *server = NFS_SERVER(inode);
1122+
struct page *pages[NFS4XATTR_MAXPAGES];
1123+
struct nfs42_setxattrargs arg = {
1124+
.fh = NFS_FH(inode),
1125+
.xattr_pages = pages,
1126+
.xattr_len = buflen,
1127+
.xattr_name = name,
1128+
.xattr_flags = flags,
1129+
};
1130+
struct nfs42_setxattrres res;
1131+
struct rpc_message msg = {
1132+
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETXATTR],
1133+
.rpc_argp = &arg,
1134+
.rpc_resp = &res,
1135+
};
1136+
int ret, np;
1137+
unsigned long timestamp = jiffies;
1138+
1139+
if (buflen > server->sxasize)
1140+
return -ERANGE;
1141+
1142+
if (buflen > 0) {
1143+
np = nfs4_buf_to_pages_noslab(buf, buflen, arg.xattr_pages);
1144+
if (np < 0)
1145+
return np;
1146+
} else
1147+
np = 0;
1148+
1149+
ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
1150+
&res.seq_res, 1);
1151+
1152+
for (; np > 0; np--)
1153+
put_page(pages[np - 1]);
1154+
1155+
if (!ret)
1156+
nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0);
1157+
1158+
return ret;
1159+
}
1160+
1161+
static ssize_t _nfs42_proc_getxattr(struct inode *inode, const char *name,
1162+
void *buf, size_t buflen)
1163+
{
1164+
struct nfs_server *server = NFS_SERVER(inode);
1165+
struct page *pages[NFS4XATTR_MAXPAGES] = {};
1166+
struct nfs42_getxattrargs arg = {
1167+
.fh = NFS_FH(inode),
1168+
.xattr_pages = pages,
1169+
.xattr_len = buflen,
1170+
.xattr_name = name,
1171+
};
1172+
struct nfs42_getxattrres res;
1173+
struct rpc_message msg = {
1174+
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETXATTR],
1175+
.rpc_argp = &arg,
1176+
.rpc_resp = &res,
1177+
};
1178+
int ret, np;
1179+
1180+
ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
1181+
&res.seq_res, 0);
1182+
if (ret < 0)
1183+
return ret;
1184+
1185+
if (buflen) {
1186+
if (res.xattr_len > buflen)
1187+
return -ERANGE;
1188+
_copy_from_pages(buf, pages, 0, res.xattr_len);
1189+
}
1190+
1191+
np = DIV_ROUND_UP(res.xattr_len, PAGE_SIZE);
1192+
while (--np >= 0)
1193+
__free_page(pages[np]);
1194+
1195+
return res.xattr_len;
1196+
}
1197+
1198+
static ssize_t _nfs42_proc_listxattrs(struct inode *inode, void *buf,
1199+
size_t buflen, u64 *cookiep, bool *eofp)
1200+
{
1201+
struct nfs_server *server = NFS_SERVER(inode);
1202+
struct page **pages;
1203+
struct nfs42_listxattrsargs arg = {
1204+
.fh = NFS_FH(inode),
1205+
.cookie = *cookiep,
1206+
};
1207+
struct nfs42_listxattrsres res = {
1208+
.eof = false,
1209+
.xattr_buf = buf,
1210+
.xattr_len = buflen,
1211+
};
1212+
struct rpc_message msg = {
1213+
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LISTXATTRS],
1214+
.rpc_argp = &arg,
1215+
.rpc_resp = &res,
1216+
};
1217+
u32 xdrlen;
1218+
int ret, np;
1219+
1220+
1221+
res.scratch = alloc_page(GFP_KERNEL);
1222+
if (!res.scratch)
1223+
return -ENOMEM;
1224+
1225+
xdrlen = nfs42_listxattr_xdrsize(buflen);
1226+
if (xdrlen > server->lxasize)
1227+
xdrlen = server->lxasize;
1228+
np = xdrlen / PAGE_SIZE + 1;
1229+
1230+
pages = kcalloc(np, sizeof(struct page *), GFP_KERNEL);
1231+
if (pages == NULL) {
1232+
__free_page(res.scratch);
1233+
return -ENOMEM;
1234+
}
1235+
1236+
arg.xattr_pages = pages;
1237+
arg.count = xdrlen;
1238+
1239+
ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
1240+
&res.seq_res, 0);
1241+
1242+
if (ret >= 0) {
1243+
ret = res.copied;
1244+
*cookiep = res.cookie;
1245+
*eofp = res.eof;
1246+
}
1247+
1248+
while (--np >= 0) {
1249+
if (pages[np])
1250+
__free_page(pages[np]);
1251+
}
1252+
1253+
__free_page(res.scratch);
1254+
kfree(pages);
1255+
1256+
return ret;
1257+
1258+
}
1259+
1260+
ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
1261+
void *buf, size_t buflen)
1262+
{
1263+
struct nfs4_exception exception = { };
1264+
ssize_t err;
1265+
1266+
do {
1267+
err = _nfs42_proc_getxattr(inode, name, buf, buflen);
1268+
if (err >= 0)
1269+
break;
1270+
err = nfs4_handle_exception(NFS_SERVER(inode), err,
1271+
&exception);
1272+
} while (exception.retry);
1273+
1274+
return err;
1275+
}
1276+
1277+
int nfs42_proc_setxattr(struct inode *inode, const char *name,
1278+
const void *buf, size_t buflen, int flags)
1279+
{
1280+
struct nfs4_exception exception = { };
1281+
int err;
1282+
1283+
do {
1284+
err = _nfs42_proc_setxattr(inode, name, buf, buflen, flags);
1285+
if (!err)
1286+
break;
1287+
err = nfs4_handle_exception(NFS_SERVER(inode), err,
1288+
&exception);
1289+
} while (exception.retry);
1290+
1291+
return err;
1292+
}
1293+
1294+
ssize_t nfs42_proc_listxattrs(struct inode *inode, void *buf,
1295+
size_t buflen, u64 *cookiep, bool *eofp)
1296+
{
1297+
struct nfs4_exception exception = { };
1298+
ssize_t err;
1299+
1300+
do {
1301+
err = _nfs42_proc_listxattrs(inode, buf, buflen,
1302+
cookiep, eofp);
1303+
if (err >= 0)
1304+
break;
1305+
err = nfs4_handle_exception(NFS_SERVER(inode), err,
1306+
&exception);
1307+
} while (exception.retry);
1308+
1309+
return err;
1310+
}
1311+
1312+
int nfs42_proc_removexattr(struct inode *inode, const char *name)
1313+
{
1314+
struct nfs4_exception exception = { };
1315+
int err;
1316+
1317+
do {
1318+
err = _nfs42_proc_removexattr(inode, name);
1319+
if (!err)
1320+
break;
1321+
err = nfs4_handle_exception(NFS_SERVER(inode), err,
1322+
&exception);
1323+
} while (exception.retry);
1324+
1325+
return err;
1326+
}

0 commit comments

Comments
 (0)